因此,在我从事的一个个人项目中,我遇到了以下问题,由于我的数学技能并不十分出色,因此我一直在努力寻找解决方案。
假设您有下面的数字树a b c d e f g h:
a
/ \
b c
/ | |
g d f
| |
h e
每下一个树意味着下一个数字大于前一个数字。所以a c还是c 让我们说我们有一个有序的数字列表,例如[a,b,c,d,e]。我们如何编写一种算法来检查列表中数字的顺序(假设L [i] I。 E,[a,c,b,d,e]和[a,b,d,c,e]都是正确的,但是[c,a,b,d,e]都不正确(因为我们知道c>一个,但与其他数字的结构无关。 出于算法的考虑,假设我们对树的访问是provably_greater(X,Y)函数,如果树知道一个数字大于另一个数字,则该函数返回true。即provably_greater(a,d)= True,但是provably_greater(d,f)= False。自然地,如果证明数字不大于,它也会返回false。 这不是 一个家庭作业问题,我已经对这个问题进行了很多抽象以使其更加清楚,但是解决该问题对于我要执行的任务至关重要。我已经尝试过几次自己破解它,但是我想出的一切最终都不足以满足我以后发现的情况。 谢谢。
答案 0 :(得分:0)
您的陈述“我想出的一切最终都不足以让我在以后发现的某些极端情况下”,这似乎使您似乎根本没有解决方案。这是蛮力算法,它在所有情况下均适用。我可以想到几种提高速度的方法,但这只是一个开始。
首先,建立一个数据结构,该结构允许基于树快速评估provably_greater(X, Y)
。此结构可以是集合或哈希表,这将占用大量内存,但允许快速访问。对于树的每片叶子,请选择一条直到根的路径。在每个节点上,查看所有后代节点,并将有序对添加到集合中,以显示这两个节点的小于关系。在示例树中,如果从节点h
开始,则上移到节点g
并将(g,h)
添加到集合中,然后上移到节点b
并添加对(b,h)
和(b,g)
到集合中,然后向上移动到节点a
并将(a,h)
,(a,g)
和(a,b)
对添加到集合中。对叶节点e
和f
执行相同的操作。由于叶子节点(a,b)
和h
,e
对将被添加到集合两次,但是集合结构可以轻松地处理此问题。
功能provably_greater(X, Y)
现在变得简单快捷:如果True
对在集合中,则结果为(Y,X)
,否则为False
。
现在,您查看列表中的所有数字对-对于列表[a,b,c,d,e]
,您将查看对(a,b)
,(a,c)
,(b,c)
等。如果provably_greater(X, Y)
对这些对中的任何对都为true,则该列表无序。否则,列表是按顺序排列的。
使用Python之类的语言实现起来应该很容易。让我知道您是否需要一些Python 3代码。
答案 1 :(得分:0)
我将忽略您的provably_greater函数,并假定访问树,以便提供高效的算法。
首先,对树进行一次Euler游览,记住每个节点的开始索引和结束索引。如果使用同一棵树来检查许多列表,则只需执行一次。参见https://www.geeksforgeeks.org/euler-tour-tree/
创建一个最初为空的索引二进制搜索树
遍历列表。对于每个节点,请检查树是否在其开始和结束Euler巡回索引之间包含任何索引。如果是这样,则列表是乱序的。如果不是,则将其起始索引插入树中。这样可以防止任何较小的节点出现在列表的后面。
就是这样-对于每个列表,总共为O(N log N)。
二进制搜索树可以使用Java中的TreeSet
或C ++中的std::set
。