Leetcode22——括号生成(回溯法)
1. 写在前面
回溯[sù]
:意思是逆着水流的方向走、逆水而行,逆流而上
1
。我一直读成[shuò]。
框[kuàng]架
:
1.建筑工程中,由梁、柱等联结而成的结构:完成主体~工程。
2.比喻事物的基本组织、结构:这部长篇小说已经有了一个大致的~。
得,语文没学好。
2. 回溯法基本思想
在许多递归问题当中,我们采取的方法都是穷尽所有的可能,从而找出合法的解。但是在某些情况下,当递归到某一层的时候,根据设置的判断条件,可以 judge 此解是不合法的。在这种情况下,我们就没必要再进行深层次的递归,从而可以提高算法效率。这一类算法我们称为“回溯法”,设置的判断条件称为“剪枝函数”。
2
个人觉得啊,回溯法可以类比为一棵自上而下的树,每一次
满足题目要求
的选择就是一个节点。当
满足题目结束条件
时,根到当前叶子节点的路径就是一个可行解。
3. 回溯法基本框架
回溯法框架
3
1、路径:也就是已经做出的选择。
2、选择列表:也就是你当前可以做的选择。
3、结束条件:也就是到达决策树底层,无法再做选择的条件。
代码方面,回溯算法的框架:
result = []
def backtrack(路径, 选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择
其核心就是 for 循环里面的递归,在递归调用之前「做选择」,在递归调用之后「撤销选择」,特别简单。
4. 题目描述
- 括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例:
输入:n = 3
输出:[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
5. 代码
参考回溯法框架三点的解题。
- 1.路径:也就是已经做出的选择。 ->这里使用StringBuilder保存已走路径,方便到时候回溯 — stringBuilder.deleteCharAt(X);
-
2.选择列表:也就是你当前可以做的选择。 ->每次都可以选择 左括号 或者 右括号,但有限制条件:
1.左右括号数量均不能超过n。2.当前StringBuilder的右括号数量必须小于左括号数量
。 - 3.结束条件:也就是到达决策树底层,无法再做选择的条件。->StringBuilder长度为2*n。
List<String> result = new ArrayList<String>();
public List<String> generateParenthesis(int n) {
//1、路径:也就是已经做出的选择。
StringBuilder stringBuilder = new StringBuilder();
//本题有两个需要注意:
// 1.左括号和右括号数目均不能超过n
// 2.如何判断括号合法?————————————————————当前已保存的括号数关系需满足:right括号数 <= left括号数。
backTrack(n, 0, 0, stringBuilder);
return result;
}
/**
* 回溯计算
*
* @param num 括号对数
* @param leftNum 已有左括号数量
* @param rightNum 已有右括号数量
* @param stringBuilder 已保存的路径
*/
private void backTrack(int num, int leftNum, int rightNum, StringBuilder stringBuilder) {
//结束条件
if (stringBuilder.length() >= num * 2) {
result.add(stringBuilder.toString());
return;
}
//做选择
if (leftNum < num) {
stringBuilder.append("(");
backTrack(num, ++leftNum, rightNum, stringBuilder);
//撤销选择
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
--leftNum;
}
//咱再做一次选择
if (rightNum < leftNum) {
stringBuilder.append(")");
backTrack(num, leftNum, ++rightNum, stringBuilder);
//撤销选择
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
--rightNum;
}
}
6. 总结
一开始做题用的是暴力递归法,当括号总数达到2*n时才判断括号是否有效”((((((“,看了题解之后才知道回溯法。回溯法题目做的还是不多,得多刷几题找找感觉。加油!
/**
* 判断括号是否有效
* @param array char数组
* @return 是否有效
*/
private boolean parenthesIsValid(char[] array) {
int balance = 0;
for (char c : array) {
if ('(' == c) {
balance++;
} else {
balance--;
}
if (balance < 0) {
return false;
}
}
return balance == 0;
}
完~
版权声明:本文为weixin_42683408原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。