算法039(必备)——嵌套类问题的递归解题套路

一、基本计算器Ⅲ

思路:

1. 确定递归函数:

  • 计算括号内的数学表达式,并返回计算结果

2.大体流程(递归):

遍历字符串,直到遇到尾或‘)’:

  • 遇到数字:将其压入到容器中
  • 遇到操作符:在将其压入到容器前,若操作池的顶部是乘除,则计算数字池顶部并再次压入到数字池中
  • 遇到'(' :进入递归并将结果压入到数字池中,并利用全局变量where记录递归后要遍历的位置

遍历完成后,注意末尾数字的遗漏计算问题(根据流程需要遇到字符才能将其压入)。

计算结果

更新where

代码:

class Solution {
public:
    int where;
    void push(vector<int>& num_vec, vector<char>& opt_vec, int cur) {
        if (!opt_vec.size()) {
            num_vec.push_back(cur);
            return;
        }
        if (opt_vec.back() == '*') {
            cur *= num_vec.back();
            num_vec.pop_back();
            num_vec.push_back(cur);
        } else if (opt_vec.back() == '/') {
            cur /= num_vec.back();
            num_vec.pop_back();
            num_vec.push_back(cur);
        }
        else num_vec.push_back(cur);
    }
    int cal(vector<int>& num_vec, vector<char>& opt_vec){
        if(num_vec.size()==0)return 0;
        int n=num_vec.size();
        int ret=num_vec[0];
        for(int i=1;i<n;++i){
            if(opt_vec[i-1]=='+'){
                ret+=num_vec[i];
            }else ret-=num_vec[i];
        }
        return ret;
    }
    int f(string s, int i) {
        vector<int> num_vec;
        vector<char> opt_vec;
        int cur = 0;
        int len = s.size();
        while (i < len && s[i] != ')') {
            if (s[i] <= '9' && s[i] >= '0') {
                cur = cur * 10 + (s[i++] - '0');
            } else if (s[i] == '(') {
                cur=f(s,i+1);
                i=where+1;
                // push(num_vec,opt_vec,cur);
                // cur=0;
            } else if(s[i]!=' '){
                push(num_vec,opt_vec,cur);
                cur = 0;
                opt_vec.push_back(s[i++]);
            }else ++i;
        }
        //cout<<cur<<endl;
        // if(cur)
        push(num_vec,opt_vec,cur);
        where=i;
        return cal(num_vec,opt_vec);
    }

    int calculate(string s) { return f(s, 0); }
};

二、字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

思路:

1. 确定递归函数:

  • 解码括号内的字符串,并返回解码后的结果

2.大体流程(递归):

遍历字符串,直到遇到尾或‘]’:

  • 遇到数字:记录直到遇到括号(与题目一不同,数字后必跟着括号)
  • 遇到字母:将其接在答案后
  • 遇到'[' :进入递归,根据返回的结果和记录的cnt,处理答案;并利用全局变量where记录递归后要遍历的位置

更新where

代码:

class Solution {
public: 
    int where;
    string f(string s,int i){
        int len=s.size();
        string ret;
        string sub;
        int cnt=0;
        while(i<len&&s[i]!=']'){
            if(s[i]<='z'&&s[i]>='a'){
                ret+=s[i++];
            }else if(s[i]=='['){
                sub=f(s,i+1);
                while(cnt--)
                {ret+=sub;}
                cnt=0;
                i=where+1;
            }else{
                cnt=cnt*10+s[i++]-'0';
            }
        }
        where=i;
        return ret;
    }
    string decodeString(string s) {
        return f(s,0);
    }
};

三、原子的数量

给你一个字符串化学式 formula ,返回 每种原子的数量 。

原子总是以一个大写字母开始,接着跟随 0 个或任意个小写字母,表示原子的名字。

如果数量大于 1,原子后会跟着数字表示原子的数量。如果数量等于 1 则不会跟数字。

  • 例如,"H2O" 和 "H2O2" 是可行的,但 "H1O2" 这个表达是不可行的。

两个化学式连在一起可以构成新的化学式。

  • 例如 "H2O2He3Mg4" 也是化学式。

由括号括起的化学式并佐以数字(可选择性添加)也是化学式。

  • 例如 "(H2O2)" 和 "(H2O2)3" 是化学式。

返回所有原子的数量,格式为:第一个(按字典序)原子的名字,跟着它的数量(如果数量大于 1),然后是第二个原子的名字(按字典序),跟着它的数量(如果数量大于 1),以此类推。

思路:

1. 确定递归函数:

  • 统计括号内的原子数量,并将结果返回到准备的容器中

2.大体流程(递归):

遍历字符串,直到遇到尾或‘)’:

  • 遇到数字:利用cnt记录结果
  • 遇到字母:若为大写字母,将之前记录的原子和cnt放置在容器中,否则更新原子名
  • 遇到'(' :进入递归,在存储返回结果和更新cnt后,处理答案;并利用全局变量where更新处理后要遍历的位置

遍历完后,注意可能的尾部原子遗漏问题(遍历过程中,需要遇到字母才会更新容器)

更新where

代码:

class Solution {
public:
    int where;
    void f(string& s, int i, unordered_map<string, int>& str_cnt) {
        int len = s.size();
        string ret;
        string sub;
        int cnt = 0;
        unordered_map<string, int> s_c;
        while (i < len && s[i] != ')') {
            if (s[i] == '(') {
                if (sub != "") {
                    str_cnt[sub] += cnt == 0 ? 1 : cnt;
                    sub = "";
                    cnt = 0;
                }
                f(s,i+1,s_c);
                i= where + 1;
                while (i < len && (s[i] <= '9' && s[i] >= '0')) {
                    cnt = cnt * 10 + s[i++] - '0';
                }
                for (pair<string, int> kv : s_c) {
                    str_cnt[kv.first] += kv.second * (cnt == 0 ? 1 : cnt);
                }
                cnt = 0;
                s_c.clear();
            } else if (!(s[i] <= '9' && s[i] >= '0')) {
                if (s[i] <= 'Z' && s[i] >= 'A' && sub != "") {
                    str_cnt[sub] += cnt == 0 ? 1 : cnt;
                    sub = "";
                    cnt = 0;
                }
                sub += s[i++];
            } else {
                while (i < len && (s[i] <= '9' && s[i] >= '0')) {
                    cnt = cnt * 10 + s[i++] - '0';
                }
            }
        }
        if(sub!="")
        str_cnt[sub] += cnt == 0 ? 1 : cnt;
        where = i;
    }

    string countOfAtoms(string formula) {
        unordered_map<string, int> str_cnt;
        map<string, int> cpy;
        string ret;
        f(formula, 0, str_cnt);
        for (pair<string, int> kv : str_cnt) {
            cpy[kv.first] = kv.second;
        }
        for (pair<string, int> kv : cpy) {
            ret+=kv.first;
            if(kv.second>1)ret+=to_string(kv.second);
        }
        return ret;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值