2020.7.21 力扣每日
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode() {} 8 * TreeNode(int val) { this.val = val; } 9 * TreeNode(int val, TreeNode left, TreeNode right) { 10 * this.val = val; 11 * this.left = left; 12 * this.right = right; 13 * } 14 * } 15 */ 16 class Solution { 17 public List<TreeNode> generateTrees(int n) { 18 if (n == 0) { 19 return new ArrayList<TreeNode>(); 20 } 21 return buildTree(1, n); 22 } 23 public List<TreeNode> buildTree(int start, int end) { 24 List<TreeNode> res = new ArrayList<TreeNode>(); 25 if (start > end){ 26 res.add(null); 27 return res; 28 } 29 if (start == end){ 30 res.add(new TreeNode(start)); 31 return res; 32 } 33 for (int i = start; i <= end; i++){ 34 List<TreeNode> leftTree = buildTree(start, i - 1); 35 List<TreeNode> rightTree = buildTree(i + 1, end); 36 for (TreeNode left : leftTree){ 37 for (TreeNode right : rightTree){ 38 TreeNode root = new TreeNode(i); 39 root.left = left; 40 root.right = right; 41 res.add(root); 42 } 43 } 44 } 45 return res; 46 } 47 }
解题思路:
该题与先前的7.15日的每日一题相似,两者都是不同的二叉搜索树,不同的是,先前只需返回总数,而该题需要返回所有的树,但解题思路是相似的,要解决根节点的情况就要解决左右子树的情况,这里同样可以使用动态规划来实现,但此处先用递归来实现,便于理解。根据二叉搜索树的性质,显然,i作为根节点时的左子树范围为[0,i - 1],右子树范围为[i+1,n],同样,其余子树的情况也可用该形式表示,不过其start与end并非0与n,需要根据父节点的传入参数决定。设计好递归参数后,我们便需设计递归函数内部。
注意点:
- 首先对于递归函数的返回值,显然是一个List<TreeNode>数组,用于存储不同的子树的根节点。所以递归函数内先定义一个res,作为结果传出。
- 其次对于子树来说,其根节点的内容是会变化的,即定义一个参数i,遍历范围为[start,end],作为跟节点所有可能的情况。
- 接着便使用递归求左右子树的情况,即定义新的leftTree,rightTree数组,来存储左右子树返回的结果。
- 最后利用两个for循环,遍历左右子树的所有情况,将其与root连接,再将root节点添加入res内继续向上返回即可。
- 由于每两个不同的left,right子树将会是一个不同的子树,所以root的根节点创建需在两个for循环内部,即每次都使用new TreeNode(i),创建新的root节点。
空间复杂度与时间复杂度的计算涉及到卡特兰数,自行查阅理解。