力扣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/
雪儿言