力扣LeedCode动态规划专题中等题(八)

面试题 08.09. 括号

题目:

括号。设计一种算法,打印n对括号的所有合法的(例如,开闭一一对应)组合。

说明:解集不能包含重复的子集。

例如,给出 n = 3,生成结果为:

[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]

题解:

采用回溯的思想,边界条件是字符串temp的长度是n*2的时候终止,并返回。
把字符串temp追加到不定长数组vec后面
如果左括号少于n,则添加左括号
如果右括号少于左括号,则添加右括号

代码:

 1 class Solution {
 2     vector<string> vec;
 3 public:
 4     //采用回溯的思想,边界条件是字符串temp的长度是n*2的时候终止,并返回。
 5     void dfs(int l,int r,string temp,int n)
 6     {
 7         if(temp.length()==n*2)
 8         {
 9             vec.push_back(temp);//把字符串temp追加到不定长数组vec后面
10         }
11         if(l<n)//如果左括号少于n,则添加左括号
12         dfs(l+1,r,temp+'(',n);
13         if(r<l)//如果右括号少于左括号,则添加右括号
14         {
15             dfs(l,r+1,temp+')',n);
16         }
17     }
18     vector<string> generateParenthesis(int n) {
19         dfs(0,0,"",n);//dfs的初始条件
20         return vec;//返回字符串不定长数组vec
21     }
22 };

 

894. 所有可能的满二叉树

 题目:

 

满二叉树是一类二叉树,其中每个结点恰好有 0 或 2 个子结点。

返回包含 N 个结点的所有可能满二叉树的列表。 答案的每个元素都是一个可能树的根结点。

答案中每个树的每个结点都必须有 node.val=0。

你可以按任何顺序返回树的最终列表。

 

题解:

            //这里就是递归的精髓了,每次看到递归,就一头雾水

            //在这里,我们不用去关心左右子树是怎么递归形成的
            //我们可以仅仅去关心,这个函数,它实现的是什么功能
            //allPossibleFBT(i)返回了一个列表,它存放着当结点数为i时,所有满足条件的树的root的集合
            //我们可以认为,allPossibleFBT(i)存放着所有满足条件的左子树的集合
            //同样,allPossibleFBT(N-1-i)存放着所有满足条件的右子树的集合
            //这是由vector<TreeNode*> allPossibleFBT(int N)这个函数的定义所确定的

 代码:

 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11     vector<TreeNode*> temp;
12 public:
13     //得到一个列表,存放着所有满足条件的树的root
14     vector<TreeNode*> allPossibleFBT(int N) {
15         vector<TreeNode*> dp;
16 
17         //边界条件1:如果输入的是偶数,return一个空列表
18         if(N & 1 == 0) return dp;
19         //边界条件2:如果输入为1,那么结果就只有一个值为0的结点
20         if(N == 1) {dp.push_back(new TreeNode(0));return dp;}
21 
22         //我们知道一共有N个结点,root占了1个结点,左子树可能有1,3,5,..,N-2个结点
23         //对应的,右子树可能有N-2,..,5,3,1个结点
24         //那么,我们可以用一个循环,找到所有可能的左右子树的可能的数量的情况,把root放进列表里
25         for(int i=1;i<=N-2;i+=2){
26             //这里就是递归的精髓了,每次看到递归,就一头雾水
27             //在这里,我们不用去关心左右子树是怎么递归形成的
28             //我们可以仅仅去关心,这个函数,它实现的是什么功能
29             //allPossibleFBT(i)返回了一个列表,它存放着当结点数为i时,所有满足条件的树的root的集合
30             //我们可以认为,allPossibleFBT(i)存放着所有满足条件的左子树的集合
31             //同样,allPossibleFBT(N-1-i)存放着所有满足条件的右子树的集合
32             //这是由vector<TreeNode*> allPossibleFBT(int N)这个函数的定义所确定的
33             vector<TreeNode*> left = allPossibleFBT(i);
34             vector<TreeNode*> right = allPossibleFBT(N-1-i);
35 
36             //接下来,就是左右子树的排列组合,当左子树为m时,右子树可能有right.size()个可能
37             //所以一共有right.size() * left.size()种可能
38             //我们把每一种排列,都放到我们所要的结果中
39             for(int j=0;j<left.size();++j){
40                 for(int k=0;k<right.size();++k){
41                     TreeNode *root = new TreeNode(0);
42                     root->left = left[j];
43                     root->right = right[k];
44                     //对于左子树有i个结点,右子树有N-1-i个结点时,我们把所有可能的树push进入队列
45                     dp.push_back(root);
46                 }
47             }
48         }
49         //所以说,看到递归,我们可以屏蔽掉复杂的递归思考过程,而是单纯的把递归函数本身,看成一个封装完全
50         //功能独立的一个函数。
51         return dp;
52     }
53 };

 

 

参考链接:https://leetcode-cn.com/problems/bracket-lcci

https://leetcode-cn.com/problems/bracket-lcci/solution/c-by-fanko/

https://leetcode-cn.com/problems/all-possible-full-binary-trees

 https://leetcode-cn.com/problems/all-possible-full-binary-trees/solution/cban-ben-fu-dai-wan-zheng-de-zhu-shi-by-fuckleetco/

 

posted @ 2021-07-22 15:21  白雪儿  Views(72)  Comments(0Edit  收藏  举报