PS: 本文记录几个经常遇到的 括号问题,其中包括: 有效括号判断、括号生成、最长有效括号等。
有效括号判断
题目分析: 读题过后,很自然想到一个游戏——《消消乐》,只要遇到成对的()就能抵消,然后最终判断最后剩下的是不是不能成对的,即还有元素则判断为无效括号,否则为有效括号。此题这里借助辅助栈来完成。
class Solution {
public:
bool isValid(string str) {
// 使用栈结构
stack<char> left;
for (auto c : str) {
if (c == '(' || c == '[' || c == '{') {
left.push(c);
}
else { // 字符是‘)’ 或者 ‘]’ 或者 ‘}’
if (!left.empty() && leftOf(c) == left.top()) {
left.pop();
}
else {
// 和最近的左括号不匹配
return false;
}
}
}
// 是否所有的左括号都被匹配了
return left.empty();
}
char leftOf(char c) {
if (c == ')') return '(';
if (c == ']') return '[';
return '{';
}
};
括号生成
题目分析: 初看题目,有点像字符串的排列,故很容易往 dfs 那个方面去想,但是我觉得dfs的构造还是比较难想到(太菜),这里主要是通过控制 "(" 和 “)”的数量来进行深搜,请直接看代码。
// dfs
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> res;
if (n == 0) return res;
dfs("", 0, 0, n, res);
return res;
}
/**
* @param curStr 当前递归得到的结果
* @param left 左括号已经用了几个
* @param right 右括号已经用了几个
* @param n 左括号、右括号一共得用几个
* @param res 结果集
*/
void dfs(string curStr, int left, int right, int n, vector<string>& res) {
// 递归终止条件
if (left == n && right == n) {
res.push_back(curStr);
}
// 剪枝
if (left < right) {
return;
}
if (left < n) {
dfs(curStr + "(", left + 1, right, n, res);
}
if (right < n) {
dfs(curStr + ")", left, right + 1, n, res);
}
}
};
动态规划方法(https://leetcode-cn.com/problems/generate-parentheses/solution/zui-jian-dan-yi-dong-de-dong-tai-gui-hua-bu-lun-da)
class Solution3 {
public:
vector<string> generateParenthesis(int n) {
if (n == 0) return {};
if (n == 1) return { "()" };
vector<vector<string>> dp(n + 1);//定义状态 dp[i]:使用 i 对括号能够生成的组合。
dp[0] = { "" }; // 0组括号时记为None
dp[1] = { "()" }; //# 1组括号只有一种情况
for (int i = 2; i <= n; i++) { // # 开始计算i组括号时的括号组合
for (int j = 0; j < i; j++) {
for (string p : dp[j]) //开始遍历 p q ,其中p+q=i-1 , j 作为索引
for (string q : dp[i - j - 1]) {
string str = "(" + p + ")" + q; //dp[i] = "(" + dp[可能的括号对数] + ")" + dp[剩下的括号对数]
dp[i].push_back(str);
}
}
}
return dp[n];
}
};
最长有效括号
题目分析:
方法一: 基于有效括号那一题,很容易想到用stack 来解决,这里的编程思想为,使用stack 来记录 “(” 出现的下标,当“)”出现时, 弹出栈顶元素,并在此时更新最长有效括号的长度信息。
class Solution {
public:
int longestValidParentheses(string s) {
int max_length = 0;
stack<int> sta;
sta.push(-1);
for (int i = 0; i < s.size(); i++) {
if (s[i] == '(') {
sta.push(i);
}
else {
sta.pop();
if (sta.empty()) {
sta.push(i);
}
else {
max_length = max(max_length, i - sta.top());
}
}
}
return max_length;
}
};
方法二: (动态规划)
class Solution {
public:
int longestValidParentheses(string s) {
int max_length = 0;
vector<int> dp(s.size());
for (int i = 1; i < s.size(); i++) {
if (s[i] == ')') {
if (s[i - 1] == '(') {
if (i >= 2) {
dp[i] = dp[i - 2] + 2;
}
else {
dp[i] = 0 + 2;
}
}
else if (i - dp[i - 1] > 0 && s[i - dp[i - 1] - 1] == '(') {
if (i - dp[i - 1] >= 2) {
dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2;
}
else {
dp[i] = dp[i - 1] + 0 + 2;
}
}
max_length = max(max_length, dp[i]);
}
}
return max_length;
}
};