• 字符串中的匹配之递归


    字符串的括号匹配是一个很常见的问题。用栈这种后进先出的结构是非常适合的。此外,字符串中的回文以及衍生的各种问题也是字符串处理中非常常见的。

    今天再说一下这类相似的问题,如何用递归来转化成子结构来求解。

    先放一条LeetCode例题: 680. Valid Palindrome II

    Given a non-empty string s, you may delete at most one character. Judge whether you can make it a palindrome.
    Example 1:
    Input: "aba"
    Output: True

    Example 2:
    Input: "abca"
    Output: True

    题目的意思是:至多删除一个字母判断是否能删成回文。字符串长度是50000.

    显然不能O(n^2)暴力。然后我们分析一下,其实我们只要能找出这个有问题的字母的位置在哪里就好了,然后删掉它就行了。可以通过判断是哪个字母的个数是奇数来做吗?不能,因为判断出来是什么字母,但当这个字母有很多时我们还是不知道删掉其中的哪一个。

    所以就用到所说的递归:

    两个指针从左边和右分别扫,扫到不匹配的时候就递归,分别删掉左边或右边的这个字母来判断新串是不是回文。

    注意的是,已经判断回文的部分就不需要递归了,否则就起不到递归的作用了。时间复杂度: O(n)

    AC代码:

    class Solution {
    public:
        bool isHuiwen(string& s,int l,int r){
            while (l < r){
                if (s[l] != s[r])
                    return false;
                l++;
                r--;
            }
            return true;
        }
        bool validPalindrome(string s) {
            bool res;
            int l, r;
            l = 0;
            r = s.size()-1;
            while (l < r){
                if (s[l] != s[r])
                    return isHuiwen(s, l+1, r) || isHuiwen(s, l, r-1);
                l++;
                r--;
            }
            return isHuiwen(s, 0, s.size()-1);
        }
    };
    

    再放一道LeetCode例题: 678. Valid Parenthesis String

    Given a string containing only three types of characters: '(', ')' and '*', write a function to check whether this string is valid. We define the validity of a string by these rules:

    1. Any left parenthesis '(' must have a corresponding right parenthesis ')'.
    2. Any right parenthesis ')' must have a corresponding left parenthesis '('.
    3. Left parenthesis '(' must go before the corresponding right parenthesis ')'.
    4. '*' could be treated as a single right parenthesis ')' or a single left parenthesis '(' or an empty string.
    5. An empty string is also valid.

    Example 1:
    Input: "()"
    Output: True

    Example 2:
    Input: "(*)"
    Output: True

    Example 3:
    Input: "(*))"
    Output: True

    题意就是判断是否括号匹配,其中*可任意充当(或者)或者空白。

    如果是没有*,那么做法很显然:从左到右统计(和)的个数。如果)的个数>(的个数就不行。判断到结尾的时候,如果两者个数相等就可以。

    现在引入了*这个百搭,我们同样可以用递归来做:

    如果遇到一个*,就分别把它视为左括号或者右括号或者空白来对后面的子串递归。

    AC代码:

    class Solution2 {
    public:
        int lll;
        
        bool check(string& s,int start,int lcnt,int rcnt){
            int l, r;
            l = lcnt;
            r = rcnt;
            for (int i = start; i < lll; ++i){
                if (s[i] == '(')
                    l++;
                if (s[i] == ')')
                    r++;
                if (r > l)
                    return false;
                if (s[i]=='*'){
                    return check(s, i+1, l+1, r) ||
                           check(s, i+1, l, r+1) ||
                            check(s, i+1, l, r);
                }
            }
            return l == r;
        }
        
        bool checkValidString(string s) {
            lll = s.size();
            return check(s, 0, 0, 0);
        }
    };
    

    另外,这道题再说一个很巧妙的做法,思路来源于讨论区的高票帖。

    low代表左括号可能出现的下界,high代表左括号可能出现的上界。

    • 当遇到一个(时,low++,high++;
    • 当遇到一个)时,low--,high--;
    • 当遇到一个*时,low--,high++; (即我们既可以把*看成(也可以看成)
    • 注意的是,下界一旦小于0直接返回false代表右括号太多了, 但是上界我们得人为保证其值>=0,因为*可以被视作空白或右括号(例如"(**")。但是最后结束的时候必须保证上界为0,如果最后上界不为0就是左括号太多了。

    另附AC代码:

    class Solution {
    public:
        bool checkValidString(string s) {
            int lower = 0, upper = 0;
            for (char c : s) {
                if (c=='(') {
                    lower++;
                    upper++;
                } else if (c==')') {
                    lower--;               
                    upper--;
                } else { // * encountered
                    lower--;
                    upper++;
                }
                lower = max(lower, 0);
                if (upper<0) // unmatched ')' found in the middle of string
                    return false;
            }
            return lower==0;
        }
    };
    
  • 相关阅读:
    ubuntu 20.04中配置静态固定IP
    R语言中安装包常见的3种来源
    centos 7.9.2009中安装 R、Rstudioserver
    ubuntu 20.04 中安装Rstudioserver
    Centos7 安装R语言并安装R包
    linux 中netstat命令
    十六进制颜色对照表
    Cesium 获取当前场景坐标范围
    使用ArcMap中的工具时,总是弹出windows安全警告窗口解决方法_会握爪的小金毛的博客
    Cesium 解决两个billboard重叠问题_easyCesium的博客
  • 原文地址:https://www.cnblogs.com/ohazyi/p/7538554.html
Copyright © 2020-2023  润新知