LeetCode刷题记录--字符串

1. IP地址复原

LeetCode刷题记录--字符串_第1张图片

1. 官方回溯法(推荐,DFS深刻理解)

使用dfs,维护一个段变量表示现在处理的是目标IP地址的第几段,同时维护一个起始位置,表明目前处理的是string的第几位。
这里还是没有对DFS的核心思想理解到位,最核心的就是在下面代码的一般情况中,这里使用了一个新变量END,没有在原变量Begin上操作,这就保证了在确定Begin能够被完整遍历的情况下,完成每个首位的DFS。

class Solution {
private:
    static const int SEGNUM = 4;  //这里所有的dfs共享一个SEGNUM变量,所以设置为static,因为不打算改变它,所以设置为const
public:
    vector<string> Res;
    vector<int> segments{0,0,0,0};

    void dfs(const string& s, int SegID, int Begin){
        //如果是第4段且已经遍历完了,则是一个答案
        if(SegID==SEGNUM){
            if(Begin==s.size()){
                string ipAddr;
                for(int i=0; i<SEGNUM; ++i){
                    ipAddr += to_string(segments[i]);
                    //在前三段后面加上.
                    if(i!=SEGNUM-1){
                        ipAddr+=".";
                    }
                }
                // move将一个左值转换为对应的右值的引用。(左值代表身份,右值代表值本身)
                Res.push_back(move(ipAddr));  //所引用的对象即将销毁;该对象无其他用户。
            }
            return;
        }
        //如果没有到达第四段就已经到底了,说明这个不是,提前回溯
        if(Begin==s.size())  return;
        //处理开头为0的情况,直接这一位为0
        if(s[Begin]=='0'){
            segments[SegID]=0;
            dfs(s, SegID+1, Begin+1);
        }

        //如果是一般情况,就dfs取每一段然后接着下一段
        int addr = 0;
        for(int End=Begin; End<s.size(); ++End){
            addr = addr*10+(s[End]-'0');
            if(addr>0 && addr<=255){
                segments[SegID] = addr;
                //dfs递归调用到底,到底之后再依次往上回溯,保证END会遍历完,就是DFS的回溯机制。
                dfs(s, SegID+1, End+1);  
            }
            else break;
        }
        
    }

    vector<string> restoreIpAddresses(string s) {
        dfs(s, 0, 0);
        return Res;
    }
};

2. 暴力解法(好理解,但是不推荐)

这种很容易看出来,对每个位遍历3次,取出来,当位数满足s长度时才进行后面的组合,组合之前先check每部分是否符合。当遇到先导0且不止1位时,return false,组合之后如果在[0,255]内就是一个答案,组合之。

思路很简单直接,但是这不是本题的目的。

class Solution {
private:
    static const int SEGNUM = 4;  //这里所有的dfs共享一个SEGNUM变量,所以设置为static,因为不打算改变它,所以设置为const
public:
    vector<string> Res;
    vector<int> segments{0,0,0,0};

    bool check(string s){
        int num=0;
        //先导0不算
        if(s[0]=='0' && s.size()>1) return false; 
        for(int i=0; i<s.size(); ++i){
            num = num*10 + s[i]-'0';
        }
        if(num>=0 && num<=255) return true;
        else return false;
    }

    vector<string> restoreIpAddresses(string s) {
        for(int i=1; i<4; ++i){ 
            for(int j=1; j<4; ++j){        
                for(int k=1; k<4; ++k){        
                    for(int l=1; l<4; ++l){
                        //截取
                        if(i+j+k+l==s.size()){
                            string a = s.substr(0,i);
                            string b = s.substr(i, j);
                            string c = s.substr(i+j, k);
                            string d = s.substr(i+j+k, l);
                            if(check(a) && check(b) && check(c) && check(d))
                                Res.push_back(a+"."+b+"."+c+"."+d);
                        }
                    }
                }   
            }
       }
        return Res;
    }
};

3. 本题小结

  1. 还是要深刻理解DFS的精髓,在一个方向上DFS之后,后面还有别的代码,这里的代码相对于这个DFS是回溯的。

2. BM44 有效括号序列

LeetCode刷题记录--字符串_第2张图片

1. 自己和官方的栈

两种方法本质思路都一样,一种是把左括号入栈,另一种是读入了左括号,把对应的右括号入栈;然后遇到右括号时出栈比较。
自己的:

class Solution {
public:
    /**
     * 
     * @param s string字符串 
     * @return bool布尔型
     */
    bool isValid(string s) {
        // write code here
        if(s.length()==0) return true;
        stack<char> sta;
        for(int i=0; i<s.length(); ++i){
            //左括号入栈
            if(s[i]=='(' || s[i]=='{' || s[i]=='[')
                sta.push(s[i]);
            //右括号,要出栈
            else{
                //栈为空则无对应,false
                if(sta.empty()) return false;
                else{
                    if(s[i]==')' && sta.top()=='(') sta.pop();
                    else if(s[i]=='}' && sta.top()=='{') sta.pop();
                    else if(s[i]==']' && sta.top()=='[') sta.pop();
                    else return false;
                }
            }
        } //end for
        if(!sta.empty()) return false;
        return true;
    }
};

官方右括号入栈:

bool isValid(string s) {
    stack<char> stk;
    for(int i=0;i<s.size();i++){
        if(s[i] == '(')           //当为(字符时,将匹配字符入栈,下同
            stk.push(')');
        else if(s[i] == '[')
            stk.push(']');
        else if(s[i] == '{')
            stk.push('}');
        else{                //当字符不是'(','[','{'这三种字符时,则判断当前字符是否与栈顶元素一样(栈非空时)
            if(stk.empty() || s[i] != stk.top())
                return false;
            stk.pop();
        }
    }
    return stk.empty();
}

2. 本体小结

灵活使用栈。

你可能感兴趣的:(C++编程,算法与数据结构,leetcode,深度优先,算法)