在二叉搜索树中查找有效序列

时间:2015-11-17 22:27:44

标签: algorithm binary-search-tree sequences

假设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。

是否有必要制作图案?写一个最小的形式属性来检查。 感谢。

3 个答案:

答案 0 :(得分:1)

转到此处:https://www.cs.usfca.edu/~galles/visualization/BST.html在左上角一次放入每个号码,在'插入'旁边,然后点击'插入'。输入数字时,它将构建一个二叉树。

为每个序列执行此操作并比较它们的外观。

这是通过" a)":

的路线

tree for sequence A

它是一个单一的链条。这是尝试通过" c)":

的路线

enter image description here

它不是从上到下的单一路径,它有一个错误的转弯分支。如果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

优化:

我们可以使用 maxmin 变量来结转有效范围 - 记忆

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。所以无效