持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
题目
给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。
示例 1
输入:n = 3
输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]
示例 2
输入:n = 1
输出:[[1]]
提示:
- 1 <= n <= 8
题解
思路
先定义一个子过程F,这个过程会递归调用。既然是递归调用就要考虑下层怎么调,边界是什么,主函数怎么调。
下层怎么调用:
- 既然是二叉搜索树,那就有左小右大的特点,那么左右两个数是否就能作为下层调用的参数呢
- 为了方便,用数组[3,4,5,6,7]来举例。
- 遍历数组
- 以3为头节点的时候,[4,5,6,7]为右子树结点集合生成,此时会调用F(4,7),左子树为空,会调用F(3,2),此时参数不合法返回空集合
- 以4为头节点的时候,[3,]为左树集合的生成,会调用F(3,3),右树[5,6,7],会调用F(5,7)
- 以5为头节点的时候,[3,4]为左树集合的生成,会调用F(3,4),右树[6,7],会调用F(6,7)
- 以6为头节点的时候,[3,4,5]为左树集合的生成,会调用F(3,5),右树[7],会调用F(7,7)
- 以7为头节点的时候,[3,4,5,6]为左子树结点集合生成,此时会调用F(3,6),左子树为空,会调用F(8,7),此时参数不合法返回空集合
- 为什么不用1开头的数组来举例,是希望你能在过程中理解递归,[3,4,5,6,7]其实是长度为7的数组以2为头节点的时候的一个右子树过程
边界是什么:
- 通过上面的分析,传进来的参数如果左大于右(l>r)那就直接定义为不合法
- 如果传进来的参数有l==r,那么直接返回由一个值形成的集合
主函数怎么调用
f(1,n)- 从1到n作为根结点得到的树集合递归算好往上发给我
代码
func generateTrees(n int) []*TreeNode {
return getRestNumRoot(1, n)
}
// 参数说明:l,r表示在[l,r]范围上,每个数字作为根节点时能得到的树 对应的根节点集合
// 以下举例都用[3,4,5,6,7]来举例,不用从1开始是为了让你更直观理解递归过程
func getRestNumRoot(l, r int) []*TreeNode {
if l > r {
// l都跑到r旁边了自然返回的是空集合 这种情况有两种可能
// ①遍历到3结点作为根,此时左子树为空,因为这是递归调用是getRestNumRoot(3,2)
// ②遍历到7结点作为根,此时右子树为空,递归调用是getRestNumRoot(8,7)
return []*TreeNode{}
}
if l == r {
// 这种情况也好理解,不需要挨个去创建根节点,直接将只包含一个值的数组返回即可
// 举例:以4为根节点 左子树调用getRestNumRoot(3,3)
return []*TreeNode{
&TreeNode{Val: l},
}
}
ret := []*TreeNode{}
// 循环尝试将[l,r]范围上每个数字都作为头节点
for m := l; m <= r; m++ {
leftTreeSet := getRestNumRoot(l, m-1) // 左边则是[l..m-1] 自己递归算好传上来给我
rightTreeSet := getRestNumRoot(m+1, r) // 右边则是[m+1..r] 自己递归算好传上来给我
if len(leftTreeSet) == 0 {
// 左树为空的时候说明右数一定有内容 挨个拼就行了
for i := 0; i < len(rightTreeSet); i++ {
root := &TreeNode{
Val: m,
Left: nil,
Right: nil,
}
root.Right = rightTreeSet[i]
ret = append(ret, root)
}
} else if len(rightTreeSet) == 0 {
// 同理
for i := 0; i < len(leftTreeSet); i++ {
root := &TreeNode{
Val: m,
Left: nil,
Right: nil,
}
root.Left = leftTreeSet[i]
ret = append(ret, root)
}
} else {
// 左右根节点集合都有内容 左边集合拿一个 右边集合拿一个 拼一起就好了
for i := 0; i < len(leftTreeSet); i++ {
for j := 0; j < len(rightTreeSet); j++ {
root := &TreeNode{
Val: m,
Left: nil,
Right: nil,
}
root.Left = leftTreeSet[i]
root.Right = rightTreeSet[j]
ret = append(ret, root)
}
}
}
}
return ret
}
结语
业精于勤,荒于嬉;行成于思,毁于随。