• Leetcode 括号匹配


    括号表达式匹配的条件:从左往右,左括号个数大于等于右括号个数,且最后左右括号数相等。

    LC 921. 使括号有效的最少添加

    题目:添加最少数目的左括号或右括号,使得表达式有效
    方法:
    贪心,遇到右括号,能匹配就匹配,不能匹配就答案加1。
    为什么这是最少的次数就不会证明了...

    class Solution {
    public:
        int minAddToMakeValid(string s) {
            int left = 0, ans = 0;
            for(char ch : s) {
                if(ch == '(')  left++;
                else {
                    if(left == 0)  ans++;
                    else left--;
                }
            }
            return ans+left;
        }
    };
    

    LC 1541. 平衡括号字符串的最少插入次数

    题目:与上题92稍有不同,一个左括号要匹配两个连续的右括号。
    方法:记录左括号个数,遇到两个右括号就匹配掉,左括号/右括号不够时都需要补充,同时答案加1

    class Solution {
    public:
        int minInsertions(string s) {
            int left = 0;
            int i = 0, n = s.size();
            int ans = 0;
            while(i < n) {
                // cout << i << " " << left << " " << ans << endl;
                if(s[i] == '(') {left++; i++;}
                else {
                    if(i < n-1 && s[i+1] == ')')  i += 2;  // 连续两个'('
                    else {   // 只有一个'(',补一个
                        i += 1;  
                        ans++;  
                    }
                    if(left)  left--;
                    else  ans++;  // 补个左括号  
                }
            }
            return ans + left*2;
        }
    };
    

    LC 1963. 使字符串平衡的最小交换次数

    题目:字符串 恰好 由 n / 2 个开括号 '[' 和 n / 2 个闭括号 ']' 组成。返回使 s 变成 平衡字符串 所需要的 最小 交换次数。
    方法:
    贪心。从前往后,能匹配就匹配,不能匹配就交换。
    不会证明正确性。

    class Solution {
    public:
        int minSwaps(string s) {
            int i = 0, j = s.size()-1;
            int cnt = 0, ans = 0;
            for(char ch : s) {
                if(ch == '[')  cnt++;
                else {
                    if(cnt == 0) {ans++; cnt++;}
                    else cnt--;
                }
            }
            return ans;
        }
    };
    

    LC 301. 删除无效的括号

    题目:删除最小数量的无效括号,使得输入的字符串有效。要求返回所有可能的结果。
    方法:
    看似是921的翻版,但方法完全不一样。
    看这条件 1 <= s.length <= 25,暴搜无疑了。
    BFS:给定一个表达式,删除一个元素得到拓展表达式。

    class Solution {
    public:
        bool check(const string& s) {
            int left = 0;
            for(char ch : s) {
                if(ch == '(')  left++;
                if(ch == ')')  left--;
                if(left < 0)  return false;
            }
            return left==0;
        }
        vector<string> removeInvalidParentheses(string s) { 
            bool flag = false;
            vector<string>res;
            queue<string>q;
            unordered_set<string>vis;
            q.push(s);
            vis.insert(s);
            while(!q.empty()) { // BFS
                cout << "size: " << q.size() << endl;
                int size = q.size();
                for(int i = 0;i < size;i++) {  // 层次遍历
                    string s = q.front();q.pop();
                    cout << s << endl;
                    if(check(s)) { 
                        res.push_back(s);
                        flag = true;
                    }
                    if(flag)  continue;  // 如果已经找到,都不用扩展了
                    for(int j = 0;j < s.size();j++) {
                        if(s[j] != '(' && s[j] != ')')  continue;
                        string new_s = s.substr(0, j) + s.substr(j+1);
                        if(!vis.count(new_s)) {
                            vis.insert(new_s);
                            q.push(new_s);
                        }
                    }
                }
                if(flag)  break;  // 本轮已经找到了
            }
            return res;
        }
    };
    

    LC 1249. 移除无效的括号

    题目:从字符串中删除最少数目的 '(' 或者 ')' (可以删除任意位置的括号),使得剩下的「括号字符串」有效。请返回任意一个合法字符串。
    方法:
    与上一题相比,只需要返回任意一个。
    和添加一样,可以贪心得到。参考 2种解法,简洁代码,秒懂详解--[1249]

    方法一:栈(由内向外)

    把左括号入栈,右括号取栈顶匹配,所以是从内向外匹配。

    class Solution {
    public:
        string minRemoveToMakeValid(string s) {
            vector<int>removing;   // 当做栈
            for(int i = 0;i < s.size();i++) {
               if(s[i] == '(')  removing.push_back(i);  // 记录左括号的位置
               if(s[i] == ')') {
                   if(removing.size() > 0) removing.pop_back();
                   else s[i] = '*';
               }
            }
            for(int idx : removing)  s[idx] = '*';
            s.erase(remove(s.begin(), s.end(), '*'), s.end());
            return s;
        }
    };
    

    方法二:计数(由外向内)

    先统计右括号个数。再前往后遍历,遇到左括号尝试匹配,遇到右括号也先尝试匹配。

    class Solution {
    public:
        string minRemoveToMakeValid(string s) {
           int left = 0, right = count(s.begin(), s.end(), ')');
           string res = "";
           for(char& ch : s) {
               if(ch == '(') {
                   if(right > 0) {   // 如果有右括号,就一定能匹配
                       left++;
                       right--;
                       res += ch;
                   }
               }
               else if(ch == ')') {
                   if(left > 0) {  // 匹配掉一个
                        left--;
                        res += ch;
                   } 
                   else right--;  // 删除右括号,当前右括号太多了
               }
               else res += ch;
           }
           return res;
        }
    };
    

    LC 678. 有效的括号字符串

    题目:在普通的括号匹配的基础上引入*号,判断是否有效
    方法:维护一段左括号的范围[a, b]。遇到'(' a,b都加1,遇到')' a,b都减1,遇到'*' a减1 b加1

    class Solution {
    public:
        bool checkValidString(string s) {
            int a = 0, b = 0;  // 左括号的可能范围[a, b]
            for(char& ch : s) {
                if(ch == '(') a++,b++;
                else if(ch == ')') {
                    if(b < 1)  return false;
                    a = max(a-1, 0);
                    b--;
                } else {
                    a = max(a-1, 0);
                    b++;
                }
            }
            return a == 0;
        }
    };
    

    LC 2116. 判断一个括号字符串是否有效

    方法:同上题678,能修改的就相当于'*',但是像'*', '***',这些也不行,因为这里的'*'不能为空,但是可以直接用奇数长度判掉。

    class Solution {
    public:
        bool checkValidString(string s) {
            int a = 0, b = 0;  // 左括号的可能范围[a, b]
            for(char& ch : s) {
                if(ch == '(') a++,b++;
                else if(ch == ')') {
                    if(b < 1)  return false;
                    a = max(a-1, 0);
                    b--;
                } else {
                    a = max(a-1, 0);
                    b++;
                }
            }
            return a == 0;
        }
        bool canBeValid(string s, string locked) {
            int n = s.size();
            if(n & 1)  return false;
            for(int i = 0;i < n;i++) {
                if(locked[i] == '0')  s[i] = '*';
            }
            return checkValidString(s);
        }
    };
    
  • 相关阅读:
    装饰器模式(学习笔记10)
    软件设计七大原则 (学习笔记2)
    设计模式(学习笔记1)
    桥接模式 (学习笔记9)
    Mini2440裸机开发之LCD基础
    配置中心java客户端实现
    高效CSS写法
    整理电脑里面的前端开发中的小Tips【及时更新】
    IE6 position:fixed (固定定位)的解决方案
    jquery 文档操作
  • 原文地址:https://www.cnblogs.com/lfri/p/15805690.html
Copyright © 2020-2023  润新知