题目:
方法一:深度优先遍历(dfs)
思路:
不难看出,此题目的解空间树是一棵高度为n的满二叉树,按照深度优先遍历的方法,搜索所有的叶子节点,再去判断哪些是符合条件的解,返回即可,这是不难想到的。
但是,这道题目显然是可以进行剪枝的,观察一下解空间树的中间节点,可以发现只要当前节点中的右括号比左括号多,那这个分支下的叶子节点就不可能是正确的解,因此,用left代表剩余的’(’,用right代表剩余的’)’,如果left>right,直接返回即可
代码:
class Solution {
public List<String> generateParenthesis(int n) {
List<String> ans = new ArrayList();
if(n==0) return ans;
dfs(ans,"",n,n);
return ans;
}
void dfs(List<String> ans, String cur, int left , int right){
if(left==0 && right==0){
ans.add(cur);
return;
}
if(left>right)
return;
if(left>0)
dfs(ans,cur+'(',left-1,right);
if(right>0)
dfs(ans,cur+')',left,right-1);
}
}
方法二:动态规划
思路:
仅就这道题目而言,动态规划其实从时间和空间的复杂度上来说,都要比dfs来的更加复杂,但是动态规划是应当掌握的一种重要方法,应用动态规划的前提有两个:
1.最优子结构: 一个最优化策略的子策略总是最优的
2.无后效性: 如果在某个阶段上过程的状态已知,则从此阶段以后过程的发展变化仅与此阶段的状态有关,而与过程在此阶段以前的阶段所经历过的状态无关。
显然,这个问题满足以上的条件,可以使用动态规划
定义一个动态规划数组dp, 使得dp[i]表示当n==i时,所有的正确的解的集合, 因此dp中的每个元素都是一个List<String>
动态规划的核心在于状态转移方程,对于此问题,状态转移方程如下:
dp[i] = ‘(’ + dp[j]+ ‘)’ + dp[i-j-1] ( j=0,1,2…i-1)
代码:
public class Solution {
// 把结果集保存在动态规划的数组里
public List<String> generateParenthesis(int n) {
if (n == 0) {
return new ArrayList<>();
}
List<List<String>> dp = new ArrayList<>(n);
List<String> dp0 = new ArrayList<>();
dp0.add("");
dp.add(dp0);
for (int i = 1; i <= n; i++) {
List<String> cur = new ArrayList<>();
for (int j = 0; j < i; j++) {
List<String> str1 = dp.get(j);
List<String> str2 = dp.get(i - 1 - j);
for (String s1 : str1) {
for (String s2 : str2) {
cur.add("(" + s1 + ")" + s2);
}
}
}
dp.add(cur);
}
return dp.get(n);
}
}