Leetcode:1190反转每对括号间的子串(中等 ※※)

----把栈理解成左端是闭合得右端开口得容器,模拟数字整体在里面得分布情况!!
这道题类似的有 Leetcode394:字符串解码,该题的求解放在博客后面。

题目:
给出一个字符串 s(仅含有小写英文字母和括号)。
请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串,并返回最终的结果。
注意,您的结果中 不应 包含任何括号。

示例:

输入:s = "(u(love)i)"
输出:"iloveu"

思路1:
  考虑用栈的思想,因为是从内到外反转,所以就每次遇到“)”再处理,因为先遇到的右括号意味着第一批需要处理的元素出现了。除此之外其他的元素我们都给他入栈。先遇到右括号,那就出栈变成字符串,一直到遇到左括号我们不要了,然后记得把左括号也出栈,这样就实现了第一批次的反转。但是注意到反转后的元素要再次进入栈来操作啊~ 所以按顺序入栈,别慌,我们输入的是相反的,反正到时候先入后出别管,倒序不就行了~~。

class Solution {
public:
    string reverseParentheses(string s) {
        int n = s.length();
        stack<char> stk;
        for(int i = 0; i < n ; ++i) {
            if(s[i] != ')') {
                stk.push(s[i]);
            }else {
                string temp;
                while(stk.top() != '(') {
                    temp += stk.top();
                    stk.pop();
                }
                stk.pop();
                for(int j = 0; j < temp.size() ; ++j) {
                    stk.push(temp[j]);
                }
            }
        }
        int m = stk.size();
        string res(m, 0);
        for(int i = m - 1; i >= 0 ; --i) {
            res[i] = stk.top(); //从栈里面再反转
            stk.pop();
        }
        return res;
    }
};

类似的,不用栈,用数组来操作,思路一致:

class Solution {
public:
    
    string reverseParentheses(string s) {
        int n = s.size();
        string res;
        //统计当前左括号数目, 然后遇到右括号就弹出
        for(int i = 0;i < n;i++)
        {
            if(s[i] == ')') 
            {
                string temp;
                while(res.back() != '(')
                {
                    temp += res.back();
                    res.pop_back();       
                }
                res.pop_back(); //去掉括号
                res += temp;              
                // cout<<res<<endl;
            }
            else res += s[i]; 
        }
        return res;         
    }
};

思路2:
   Leetcode官方题解的第一种方法。考虑到括号是从中心到外部对称的。所以对左括号而言,遇到左括号意味着某一层的终止,将前面记录的字符串推入栈中,作为某一层字符串,然后字符串清零,继续记录。也就是说右括号的出现一定是所有左括号遍历结束之后产生的。那么当遇到右括号之后就开始操作了,第一个右括号代表最中心的一层,对他进行反转,然后放到上一层的字符尾巴,然后有新字符的话进行加入字符,这里字符就不清零了,而是每次遇到一个右括号意味着到了一层,和之前栈里面提取的元素进行大反转,然后再提取元素准备一下次。注意到刚开始stk加入了个空元素。所以最后我再准备个空元素没毛病。

class Solution {
public:
    string reverseParentheses(string s) {
        stack<string> stk;
        string str;
        for (auto &ch : s) {
            if (ch == '(') {
                stk.push(str); //左括号之前存的是一层一层的 str字符串而不是字符
                str = "";
            } else if (ch == ')') {
                reverse(str.begin(), str.end());
                str = stk.top() + str;
                stk.pop();
            } else {
                str.push_back(ch);
            }
        }
        return str;
    }
};

————————————————————————————————————————
Leetcode394:字符串解码
题目:
 1.给定一个经过编码的字符串,返回它解码后的字符串。
 2.编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
 3.你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
 4.此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

思路1:
   数字存放在数字栈,字符串和左括号存放在字符串栈,遇到右括号时候弹出一个数字栈,字母栈弹到左括号为止,然后删除左括号。 数字和字母乘法后反转返回原来字符栈(第一次实现,然后作为下一次的实现子部分),为什么要反转呢,这是因为我一开始入栈是正常顺序。现在复制了也是正常顺序入栈。最后整体反转就好了。不然因为是多层的。每次都是反的负负得正了要麻烦~
   注意到,这个方法中输入的是char,每一个char都单独进入char栈中~ 所以效率相对低一点。考虑到是否可以用string的方式一层层输入呢?请看思路2。

//数字存放在数字栈,字符串存放在字符串栈,遇到右括号时候弹出一个数字栈,字母栈弹到左括号为止。
class Solution {
public:
    string decodeString(string s) {
      string res = "";
      stack <int> nums; //建立数字栈
      stack <char> strs; //建立字符栈 但是注意到我们输入的是char所以就是char栈
      int num = 0;
      int len = s.size();
     for(int i=0; i<len; i++){
        if(s[i]>='0' && s[i]<='9')
           num=num*10+s[i]-'0';    //-'0'还是-"0"看情况把
        if(s[i]=='['){
            nums.push(num);
            num=0;
            strs.push(s[i]);
        }
        if(s[i]>='a' && s[i]<='z' || s[i]>='A' && s[i]<='Z'){
            strs.push(s[i]);
        }
        if(s[i]==']'){
            int count=nums.top();
            nums.pop();
            string stemp;
            while(strs.top()!='['){
               stemp+=strs.top();
               strs.pop();
            }
            reverse(stemp.begin(), stemp.end());
            strs.pop();
            string newstemp;
            for(int i=1;i<=count;i++){
               newstemp=newstemp+stemp;
            }
            
            for(int i=0;i<newstemp.size();i++)
               strs.push(newstemp[i]);
        }
     }
       int m=strs.size();
       for(int i=0; i<m; i++){
           res.push_back(strs.top());
           strs.pop();
       } 
       reverse(res.begin(), res.end());    
      return res;
    }
};

思路2: 碰到’[’: 数字和当前字符串入栈. 碰到 ‘]’: 数字和字符串出栈.每一次左括号会把之前积累的字符串进栈,同时完成数字记录。每次右括号当前操作的字符串没来得及进栈,那就是根据栈头就是之前积累元素的原则,根据当前的num值不断更新栈头的字符完成后。之前的元素在栈就直接丢出来。然后res就是截至当前积累的值。如果后面还是字母那就加上,如果遇到左括号说明遇到不同层得了,那就入栈。牢记,每次左括号的出现,代表进入了新的一层,**我们的原则是遇到右括号才处理,所以原则其实是从内往外操作。**因为当内嵌结构首次出现右括号,就是最里面一层。考虑到当前层出来可能还在上一层结构内,那就结合~

class Solution {
public:
    string decodeString(string s) {
        string res = "";
        stack <int> nums;
        stack <string> strs;
        int num = 0;
        int len = s.size();
        for(int i = 0; i < len; ++ i)
        {
            if(s[i] >= '0' && s[i] <= '9')
            {
                num = num * 10 + s[i] - '0';
            }
            else if((s[i] >= 'a' && s[i] <= 'z') ||(s[i] >= 'A' && s[i] <= 'Z'))
            {
                res = res + s[i];
            }
            else if(s[i] == '[') //将‘[’前的数字压入nums栈内, 字母字符串压入strs栈内
            {
                nums.push(num);
                num = 0;
                strs.push(res); 
                res = "";
            }
            else //遇到‘]’时,操作与之相配的‘[’之间的字符
            {
                int times = nums.top();
                nums.pop();
                for(int j = 0; j < times; ++ j)
                    strs.top() += res;
                res = strs.top(); //之后若还是字母,就会直接加到res之后,因为它们是同一级的运算
                                  //若是左括号,res会被压入strs栈,作为上一层的运算
                strs.pop(); //strs.top()里面的东西已经没用了 在我的res里面。
            }
        }
        return res;
    }
};
//在这里,左括号用来终结上一次的。 每一次遇到右括号就对上一层的和当前层的元素进行操作,因为当前元素没有入栈,没事直接和上一层的top叠加入栈,然后赋值给res 出栈~~~ 完美~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值