假设1到1000之间的整数排列在二叉搜索树中,并且希望找到数字363.以下一些序列,它们可能不是遍历的节点序列?
a)2,252,401,398,330,344,397,363;
b)924,220,911,244,898,258,362,363;
c)925,202,911,240,912,245,363;
d)2,399,387,219,266,382,381,278,363;
(p)e)935,278,347,621,299,392,358,363。是否有必要制作图案?写一个最小的形式属性来检查。 感谢。
答案 0 :(得分:1)
转到此处:https://www.cs.usfca.edu/~galles/visualization/BST.html在左上角一次放入每个号码,在'插入'旁边,然后点击'插入'。输入数字时,它将构建一个二叉树。
为每个序列执行此操作并比较它们的外观。
这是通过" a)":
的路线它是一个单一的链条。这是尝试通过" c)":
的路线它不是从上到下的单一路径,它有一个错误的转弯分支。如果363在树中并且你只是直接进入它,你就不会走错路。
在c)911分裂在240和912右边。
在e)中,347在621右转,在299左转。
它们不能成为363路上遍历的序列,因为每个列表中的一个节点在去往363的路上不是。
[截图来自https://www.cs.usfca.edu/~galles/visualization/BST.html]
答案 1 :(得分:1)
范围[min,max] - 初始化为[1,1000]
key - 要搜索的目标键
seq [1,N] - 二叉搜索树中的数字序列
想法是跟踪有效范围[min,max]。最初所有数字1到1000都在范围内。如果您遇到一个键为2且节目目标为363的节点,则右转。当你右转时,你在这个子树中遇到的任何键应该大于2.所以你将min范围更新为2.现在你的范围是[3,1000]。遇到252时,范围变为[253,1000]。在401,你向左转,所以子树中的所有键必须小于401.所以你将max设置为400,它变为[253,400]。
现在,在序列中的任何一点,您都需要检查该值是否在该范围内。如果没有,则存在违规行为。如果密钥匹配,则它必须是序列中的最后一个数字。
这是伪代码
boolean validate(seq[1,N],key,range)
for i from 1 to N
if(seq[i] < range.min || seq[i] > range.max)
return false
if(key < seq[i])
range.max := key-1
else if(key > seq[i])
range.min := key+1
else
return i=N
return true
答案 2 :(得分:0)
直觉:
如果 sequence[i] > sequence[i+1]
,路径已经在左子树中搜索过,并且序列中的下一个元素不能超过 sequence[i]
否则,路径包含右子树的元素,且序列中的下一个元素必须不少于sequence[i]
我们可以使用上面的逻辑来编写一个蛮力解决方案,该解决方案的时间复杂度为 O(n^2)
# checks if any elements in the sequence is greater than val
def any_element_greater(sequence, val):
for e in sequence:
if e > val:
return True
return False
# checks if any elements in the sequence is lesser than val
def any_element_lesser(sequence, val):
for e in sequence:
if e < val:
return True
return False
# checks if the sequence is valid
def is_valid_seq(sequence):
if len(sequence) < 2:
return True
prev = sequence[0]
for idx, val in enumerate(sequence):
if prev > val:
# checks if the rest of the sequence is valid based on direction
if any_element_greater(sequence[idx:], prev):
return False
elif prev < val:
# checks if the rest of the sequence is valid based on direction
if any_element_lesser(sequence[idx:], prev):
return False
prev = val
return True
优化:
我们可以使用 max
和 min
变量来结转有效范围 - 记忆
def valid_sequence(sequence, i=0, m_min=1, m_max=1000):
'''
Checks if the Sequence is a correct path in BST
Parameters:
sequence: path to the data in the BST
i: current data we are validating in the path
m_min: data should be more than m_min
m_max: data should be less than m_max
Returns:
Boolean: If the sequence is a valid path in BST
'''
if len(sequence) == 0:
return True
data = sequence[i]
# check if data is in valid range
if not (m_min <= data <= m_max):
return False
# Base case, return if we reached the end
if i == len(sequence) - 1:
return True
'''
Adjust min, max for the next data elements
depends on the next element in the sequence
'''
next = sequence[i+1]
if next > data:
m_min = max(m_min, data)
else:
m_max = min(m_max, data)
return valid_sequence(sequence, i+1, m_min, m_max)
测试:
options = {
'a': [2, 252, 401, 398, 330, 344, 397, 363],
'b': [924, 220, 911, 244, 898, 258, 362, 363],
'c': [925, 202, 911, 240, 912, 245, 363],
'd': [2, 399, 387, 219, 266, 382, 381, 278, 363],
'e': [935, 278, 347, 621, 299, 292, 358, 363]
}
for option in options:
print(f'{valid_sequence(options[option])} \t - {option}. {options[option]}')
结果:
True - a. [2, 252, 401, 398, 330, 344, 397, 363]
True - b. [924, 220, 911, 244, 898, 258, 362, 363]
False - c. [925, 202, 911, 240, 912, 245, 363]
True - d. [2, 399, 387, 219, 266, 382, 381, 278, 363]
False - e. [935, 278, 347, 621, 299, 292, 358, 363]
推理:
在选项c中,912大于911,而我们在240处进入左子树。所以它是无效的
在选项 e 中,我们从 347 开始,但我们在序列中遇到了 299 和 292。所以无效