括号生成
1. LeetCode. 22. 括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
示例 2:
输入:n = 1
输出:["()"]
class Solution {
public List<String> generateParenthesis(int n) {
List<String> ans = new ArrayList<>();
if(n == 0){
return ans;
}
backtrack(ans, n, new StringBuilder(), 0, 0);
return ans;
}
public void backtrack(List<String> ans, int n, StringBuilder sb, int open, int close){
// 左括号数量不大于 n,可以放一个左括号。如果右括号数量小于左括号的数量,可以放一个右括号
if(open>n || close>open){
return; // return才能继续查找下一个
}
if(sb.length() == 2*n){
ans.add(sb.toString());
// return; 可有可无
}
sb.append("(");
backtrack(ans, n, sb, open+1, close);
// 回溯
sb.deleteCharAt(sb.length()-1);
sb.append(")");
backtrack(ans, n, sb, open, close+1);
sb.deleteCharAt(sb.length()-1);
}
}
2. LeetCode. 20. 有效的括号
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
示例 1:
输入:s = "()"
输出:true
示例 2:
输入:s = "(]"
输出:false
示例 4:
输入:s = "([)]"
输出:false
class Solution {
public boolean isValid(String s) {
int len = s.length();
// !!!字符串长度是奇数之间判错
if(len%2 == 1){
return false;
}
// 借助Map找对应关系,更方便
Map<Character,Character> map = new HashMap<>();
map.put('(', ')');
map.put('[', ']');
map.put('{', '}');
Stack<Character> stack = new Stack<>();
for(int i = 0; i < len; i++){
if(s.charAt(i)=='(' || s.charAt(i)=='[' || s.charAt(i)=='{'){
stack.push(s.charAt(i));
}else{
if(!stack.isEmpty()){
char open = stack.pop();
if(map.get(open) != s.charAt(i)){
return false;
}
}else{
return false;
}
}
}
return stack.isEmpty();
}
}
3. LeetCode. 301. 删除无效的括号
给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。
返回所有可能的结果。答案可以按 任意顺序 返回。
示例 1:
输入:s = "()())()"
输出:["(())()","()()()"]
示例 2:
输入:s = "(a)())()"
输出:["(a())()","(a)()()"]
示例 3:
输入:s = ")("
输出:[""]
class Solution {
List<String> ans = new ArrayList<>();
public List<String> removeInvalidParentheses(String s) {
int len = s.length();
int lremove = 0;
int rremove = 0;
for(int i = 0; i < len; i++){
if(s.charAt(i) == '('){
lremove++;
}else if(s.charAt(i)==')'){
if(lremove!=0){
lremove--;
}else{
rremove++;
}
}
}
backtrack(s, 0, lremove, rremove);
return ans;
}
public void backtrack(String s, int start, int lremove, int rremove){
if(lremove==0 && rremove==0){
if(isValid(s)){
ans.add(s);
}
return;
}
for(int i = start; i < s.length(); i++){
// 去重,在每次进行搜索时,如果遇到连续相同的括号只需要搜索一次即可
if(i>start && s.charAt(i)==s.charAt(i-1)){
continue;
}
// 剪枝,如果剩余的字符无法满足去掉的数量要求,直接返回
if(lremove+rremove > s.length()-i){
return;
}
if(lremove>0 && s.charAt(i) == '('){
backtrack(s.substring(0,i)+s.substring(i+1), i, lremove-1, rremove);
}
if(rremove>0 && s.charAt(i) == ')'){
backtrack(s.substring(0,i)+s.substring(i+1), i, lremove, rremove-1);
}
}
}
public boolean isValid(String s){
int len = s.length();
int countLeft = 0;
for(int i = 0; i < len; i++){
if(s.charAt(i) == '('){
countLeft++;
}else if(s.charAt(i) == ')'){
countLeft--;
// 不要忘记下面的判断,否则出现"()())("结果
if(countLeft < 0){
return false;
}
}
}
return countLeft==0;
}
}
4. LeetCode. 32. 最长有效括号
给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例 1:
输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"
示例 2:
输入:s = ")()())"
输出:4
解释:最长有效括号子串是 "()()"
示例 3:
输入:s = ""
输出:0
class Solution {
public int longestValidParentheses(String s) {
int ans = 0;
int len = s.length();
// 为了处理边界,始终保持[栈底元素]为当前已经遍历过的元素中[最后一个没有被匹配的右括号的下标]
Stack<Integer> stack = new Stack<>();
// 为了满足栈底为[最后一个没有被匹配的右括号的下标],一开始的时候就放入值为-1的元素
stack.push(-1);
for(int i = 0; i < len; i++){
if(s.charAt(i) == '('){
stack.push(i);
}else if(s.charAt(i)==')'){
stack.pop();
// 如果栈为空,说明当前的右括号是没有被匹配的右括号,将其下标放入栈中来更新之前提到的[最后一个没有被匹配的右括号的下标]
if(stack.isEmpty()){
stack.push(i);
}else{
ans = Math.max(ans, i-stack.peek());
}
}
}
return ans;
}
}