来源:LeetCode hot 100
[1] 20.有效的括号(easy)
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。
1、JAVA题解(构建括号键值对+括号压栈判断栈空)
class Solution {
public boolean isValid(String s) {
int n = s.length();
if (n % 2 == 1) {
return false;
}
Map<Character, Character> pairs = new HashMap<Character, Character>() {
{
put(')', '(');
put(']', '[');
put('}', '{');
}};
Deque<Character> stack = new LinkedList<Character>();
for (int i = 0; i < n; i++) {
char ch = s.charAt(i);
if (pairs.containsKey(ch)) {
if (stack.isEmpty() || stack.peek() != pairs.get(ch)) {
return false;
}
stack.pop();
} else {
stack.push(ch);
}
}
return stack.isEmpty();
}
}
2、C++题解(利用括号ASCII值差+括号压栈判断栈空)
class Solution {
public:
bool isValid(string s) {
vector<char> stack;
int n = s.size();
for(int i = 0 ; i < n ; i++ ){
if(stack.empty() == true){
stack.push_back(s[i]);
}else if(s[i] - stack.back() == 1 ||s[i] - stack.back() == 2){
stack.pop_back();
}else{
stack.push_back(s[i]);
}
}
return stack.empty();
}
};
[2] 301.删除无效的括号(hard)
给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。
返回所有可能的结果。答案可以按 任意顺序 返回。
JAVA题解
class Solution {
List<String> res = new ArrayList<>();
public List<String> removeInvalidParentheses(String s) {
//计算出要移除的左右括号数
int lr = 0, rr = 0;
for(int i = 0; i < s.length(); ++i){
if(s.charAt(i) == '(') lr++;
if(s.charAt(i) == ')'){
if(lr > 0){
lr--;
}else{
rr++;
}
}
}
//进行回溯
backTrack(0, lr, rr, s);
return res;
}
//回溯,移除括号
void backTrack(int start, int lr, int rr, String s){
//完成条件:
//要移除的左右括号数都为零 且 s串有效,则添加至答案数组
if(lr == 0 && rr == 0){
if(isValid(s)) res.add(s);
}
//for s
//离开条件
//做出选择
//回溯
//撤销选择
for(int i = start; i < s.length(); ++i){
//遇到两个连续的相同括号,跳过第二个括号的处理
if(i > start && s.charAt(i) == s.charAt(i-1)) continue;
//若为左括号且要移除的左括号数大于零,则进行回溯
//s.substring(0, i) + s.substring(i + 1):表示从s中移除第i个字符后形成的新串
if(s.charAt(i) == '(' && lr > 0){
backTrack(i, lr - 1, rr, s.substring(0, i) + s.substring(i + 1));
}
if(s.charAt(i) == ')' && rr > 0){
backTrack(i, lr, rr - 1, s.substring(0, i) + s.substring(i + 1));
}
}
};
//判定是否有效
boolean isValid(String s){
Stack<Character> stack = new Stack<>();
for(int i = 0; i < s.length(); ++i){
//若该字符为右括号且栈顶为左括号,则栈顶元素出栈,跳过
if(!stack.isEmpty() && s.charAt(i)==')' && stack.peek()=='('){
stack.pop();
continue;
}
//若该字符为非括号,则跳过
if(s.charAt(i)!='(' && s.charAt(i)!=')') continue;
stack.push(s.charAt(i));
}
//返回栈的判空,若为空栈则说明有效
return stack.isEmpty();
}
}
思路整理:
1.首先遍历字符串,计算出要移除的左括号数和右括号数。(不要纠结左右括号的排列顺序,只专注于要移除的数量!作为后面回溯的资本!)
2.接着进行回溯操作,回溯完成的判断条件为【要移除的左右括号数都为零】且【s串有效】,满足则添加至答案数组。
3.返回答案。
技巧总结:
1.回溯函数尽量定义为 无返回值类型(void);
2.移除字符串中某个位置的字符可以用s.substring(0, i) + s.substring(i + 1)(表示从s中移除第i个字符后形成的新串)
3.遇到两个连续的相同括号,为了避免重复的答案,必须跳过第二个括号的处理。
4.回溯函数形参列表该怎么写,注意start参数。