面试题 04.09. 二叉搜索树序列

74 阅读3分钟

面试题 04.09. 二叉搜索树序列 - 力扣(Leetcode)

从左向右遍历一个数组,通过不断将其中的元素插入树中可以逐步地生成一棵二叉搜索树。 给定一个由不同节点组成的二叉搜索树 root,输出所有可能生成此树的数组。

示例 1:

输入: root = [2,1,3]
输出: [[2,1,3],[2,3,1]]
解释: 数组 [2,1,3][2,3,1] 均可以通过从左向右遍历元素插入树中形成以下二叉搜索树
       2 
      / \ 
     1   3

示例 2:

输入: root = [4,1,null,null,3,2]
输出: [[4,1,3,2]]

思路

这个题,看LeetCode题解就没有能讲的特别清楚的。所有的AC大佬都是自己明白,讲的不明白。让我尝试一下把这个题讲明吧。

未命名文件-导出 (19).png

以上图为例,很明确的一件事就是第一个节点必须是2。当2被选择后,接下来可以选择的是13。此时,13是供选择的,选择哪个都可以。

如果我们将供选择的节点放到一个集合中,接下来按照这个例子,走一遍流程。

最开始,供选择的节点只有根节点2。集合长下边这个样子。

未命名文件-导出 (20).png 此时,集合中供选择的只有2,我们只能拿走2。拿走2之后,下一步可供选择的节点就变成13未命名文件-导出 (21).png 那下一步中,到底是选择1还是选择3呢?事实上,1和3都是可以选择的,那就都应该尝试一下。这个题的要点就是,对于供选择的集合中的元素,都应该选择一次。 因为,在当前步骤内,既然都是可以选择的,那么每一种选择就都是一条结果路径。

未命名文件-导出 (22).png 先只拿走1,进入下一步,可供选择的节点变为3、4。 然后只拿走3,进入下一步,可供选择的节点变为1、5、6.

当可供选择的集合为空时,说明我们已经将所有的节点都选择完了,可以输出之前的选择结果。

代码

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
var res [][]int
func BSTSequences(root *TreeNode) [][]int {
   res = [][]int{}
   // 测试用例规定的,空的时候返回"[[]]"
   if root == nil {
      res = append(res, []int{})
      return res
   }

   // 开始时set中只有root, path未选取任何节点,为空。
   f(map[*TreeNode]struct{}{root:struct{}{}}, []int{})
   return res
}

// set:可供选择的节点集合
// path: 当前已经选择的节点
func f(set map[*TreeNode]struct{}, path []int) {
   // 可供选择的节点集合为空,表示已经将所有节点都选择完了
   // 可以将path添加到结果集中
   if len(set) == 0 {
      // 涉及到回溯,所以将path复制了一份
      copy := []int{}
      copy = append(copy, path...)
      res = append(res, copy)
      return
   }

   // 将每一个节点都选择一次
   for k, _ := range set {
      // 复制一份可供选择的节点集合,作为下一次选择的集合
      setNext := map[*TreeNode]struct{}{}
      for a, b := range set {
         setNext[a] = b
      }

      // 将k从可供选择的集合中拿走
      delete(setNext, k)
      // 我们已经选择了k,添加已经选择的序列中
      path = append(path, k.Val)
      // 向可供选择的集合中添加下一步可以被选择的新加入的节点
      if k.Left != nil {
         setNext[k.Left] = struct{}{}
      }
      if k.Right != nil {
         setNext[k.Right] = struct{}{}
      }

      // 来到下一步
      f(setNext, path)

      // path回溯
      path = path[:len(path)-1]
   }
}