两种问题,一个是括号的合法性,这种题目可以借助栈这种数据结构来解决
另一种是对于括号的生成,一般都要利用回溯递归的思想来解决;
括号生成
分析 如果输入3,那么就是有六个位置,每个位置有两种情况,一共有2的六次方种,全部枚举出来,然后进行条件判断,剪枝优化。
括号生成的规则 1.一个合法的括号 左括号数量一定等于右括号数量
2.对于一个合法的括号 任意子集,左括号的数量一定大于等于右括号的数量
回溯是一种用于解决组合优化问题的算法思想,它的核心思想是通过尝试不同的选择,逐步构建解空间,并在发现选择不可行时进行回退(撤销上一次的结果),以尝试其他可能的选择。
在括号生成问题中,我们需要生成符合条件的括号组合,即使在生成过程中出现了不符合条件的情况,我们也可以通过回溯来撤销上一次的结果,尝试其他可能的选择。
具体地说,回溯在每一步都有两种选择:添加一个左括号或添加一个右括号。我们通过递归调用回溯方法来尝试这两种选择,并根据当前的剩余左括号数和右括号数进行限制和判断。
如果在某一步选择添加左括号时,发现剩余的左括号数为0,或者右括号数小于左括号数(即当前的组合不符合括号的匹配规则),则需要进行回溯,撤销上一次的结果,尝试其他的选择。
同样地,如果在某一步选择添加右括号时,发现剩余的右括号数为0,或者右括号数小于左括号数,也需要进行回溯,撤销上一次的结果。
通过回溯,我们可以穷举所有可能的括号组合,并找到符合条件的组合。回溯的关键是在尝试选择后,通过撤销上一步的操作,进入下一步的选择。这样可以保证在遍历的过程中不会漏掉任何一个可能的解,同时也能够避免生成不符合条件的括号组合。
因此,回溯在解决括号生成问题中起到了关键的作用,能够有效地生成符合条件的括号组合。
代码
class Solution {
List<String> res = new ArrayList<>();
public List<String> generateParenthesis(int n) {
StringBuilder track = new StringBuilder();
//当n=3的时候,说明有6个位置,每个位置都有可能两种情况,一共是2的六次方总情况
backTracking(n, n, track);
// 需要找出符合题目要求的数量,
return res;
}
void backTracking(int left, int right, StringBuilder t) {
if (right < left) return; //说明使用的右括号多余了左括号不可理
// 数量小于 0 肯定是不合法的
if (left < 0 || right < 0) return;
if (left == 0 && right == 0) {
res.add(t.toString());
return;
}
t.append('(');//匹配左括号
backTracking(left - 1, right, t);
t.deleteCh arAt(t.length() - 1); //去掉这一个
t.append(')');//匹配左括号
backTracking(left, right - 1, t);
t.deleteCharAt(t.length() - 1); //去掉这一个
}
}
有效括号
用栈的思想来模拟,和机器人那道题思想一样的,将左边的括号加入到栈中去,遇到右边的括号进行匹配,求结果
class Solution {
public boolean isValid(String s) {
Deque<Character> deque = new LinkedList<>();
char ch;
for (int i = 0; i < s.length(); i++) {
ch = s.charAt(i);
//碰到左括号,就把相应的右括号入栈
if (ch == '(') {
deque.push(')');
}else if (ch == '{') {
deque.push('}');
}else if (ch == '[') {
deque.push(']');
} else if (deque.isEmpty() || deque.peek() != ch) {
return false;
}else {//如果是右括号判断是否和栈顶元素匹配
deque.pop();
}
}
//最后判断栈中元素是否匹配
return deque.isEmpty();
}
}
以上的代码是一个用于检查括号是否匹配的解决方案。它使用堆栈(Deque)来实现匹配的检查。
解释上面代码片段的执行过程如下:
- 创建一个空的堆栈(Deque)
deque
,用于存储右括号。 - 迭代字符串
s
中的每个字符:
a. 将当前字符存储在变量ch
中。
b. 如果ch
是左括号(‘(’,‘{’,‘[’),将其对应的右括号入栈。
- 如果ch
是 ‘(’,将 ‘)’ 入栈。
- 如果ch
是 ‘{’,将 ‘}’ 入栈。
- 如果ch
是 ‘[’,将 ‘]’ 入栈。
c. 如果堆栈为空,或者栈顶元素与当前字符ch
不相同,返回false
,表示括号不匹配。
d. 如果是右括号,则与栈顶元素进行匹配:
- 如果栈顶元素与当前字符ch
相同,则将栈顶元素出栈。
- 如果栈顶元素与当前字符ch
不相同,返回false
,表示括号不匹配。 - 完成循环后,检查堆栈是否为空。如果堆栈为空,则表示所有的括号都有匹配的右括号;否则,返回
false
。 - 最终返回结果。
例如,对于输入字符串 “([])” ,代码的执行过程如下:
- 创建一个空的堆栈
deque
。 - 迭代字符串 “([])”:
- 当前字符为 ‘(’,将 ‘)’ 入栈,栈中元素为 [‘)’]。
- 当前字符为 ‘[’,将 ‘]’ 入栈,栈中元素为 [‘)’, ‘]’]。
- 当前字符为 ‘]’,与栈顶元素匹配,栈顶元素 ‘]’ 出栈,栈中元素为 [‘)’]。
- 当前字符为 ‘)’,与栈顶元素匹配,栈顶元素 ‘)’ 出栈,栈为空。
- 完成循环后,栈为空,返回
true
,表示括号匹配。
因此,以上代码可以判断给定字符串中的括号是否匹配。如果匹配,返回 true
,否则返回 false