首页 > 其他分享 >嵌套类递归

嵌套类递归

时间:2024-10-06 15:45:59浏览次数:1  
标签:index string 递归 括号 int 嵌套 numbers formula

嵌套类递归

  • 都需要一个全局变量记录当前正在处理的位置

基础计算器 III

  • 含有嵌套的表达式求值,时间复杂度 O(n)
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Solution {
public:
    int where;

    int calculate(string &s) {
        where = 0;
        return recursive(s, 0);
    }

    // 计算 s 中从 i 位置开始到他对应的右括号结束的位置
    int recursive(string &s, int i) {
        int cur = 0;
        // 数字栈
        vector<int> numbers;
        // 符号栈
        vector<char> ops;

        while (i < s.length()) {
            if (s[i] >= '0' && s[i] <= '9') {
                // 解析数字
                cur = cur * 10 + s[i++] - '0';
            } else if (s[i] == '(') {
                // 遇到左括号,递归处理下一段表达式
                cur = recursive(s, i + 1);
                // 从 where + 1 的位置继续解析
                i = where + 1;
            } else if (s[i] == ')') {
                // 遇到右括号就退出循环
                break;
            } else {
                // 遇到运算符,把解析好的数字和这个运算符入栈,cur 清零
                push(numbers, ops, cur, s[i++]);
                cur = 0;
            }
        }
        // 最后一个数字,由于遇不到下一个运算符,所以要手动入栈
        push(numbers, ops, cur, '+');
        // 已经处理到的位置
        where = i;
        // 计算这一对括号内的表达式
        return compute(numbers, ops);
    }

    void push(vector<int> &numbers, vector<char> &ops, int cur, char op) {
        int n = numbers.size();
        if (n == 0 || ops.back() == '+' || ops.back() == '-') {
            // 栈空或者栈顶是加减运算符,就直接放入
            numbers.push_back(cur);
            ops.push_back(op);
        } else {
            // 栈顶是乘除运算,先弹出一个数字运算后,把结果入栈
            int topNumber = numbers.back();
            char topOp = ops.back();
            if (topOp == '*') {
                numbers[n - 1] = topNumber * cur;
            } else {
                numbers[n - 1] = topNumber / cur;
            }
            ops[n - 1] = op;
        }
    }

    // 计算剩下的加减运算
    int compute(const vector<int> &numbers, const vector<char> &ops) {
        int n = numbers.size();
        int ans = numbers[0];
        for (int i = 1; i < n; i++)
            ans += ops[i - 1] == '+' ? numbers[i] : -numbers[i];
        return ans;
    }
};

int main() {
    string s = "6-4/2*(3-1)+(2+1)*(5-3*2+(4/2+2))";
    Solution solution;
    cout << solution.calculate(s);
}
  • 递归(推荐),index++ 跳过左括号,而不是用 where + 1 去跳过
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Solution {
public:
    // 处理到的位置
    int index;

    int calculate(string &s) {
        return recursive(s);
    }

    // 计算 s 中从 index 位置开始到他对应的右括号结束的位置
    int recursive(string &s) {
        int cur = 0;
        // 数字栈
        vector<int> numbers;
        // 符号栈
        vector<char> ops;

        for (; index < s.length(); index++) {
            if (s[index] >= '0' && s[index] <= '9') {
                // 解析数字
                cur = cur * 10 + s[index] - '0';
            } else if (s[index] == '(') {
                // 跳过左括号
                index++;
                // 递归处理下一段表达式
                cur = recursive(s);
            } else if (s[index] == ')') {
                // 遇到右括号就退出循环
                break;
            } else {
                // 遇到运算符,把解析好的数字和这个运算符入栈,cur 清零
                push(numbers, ops, cur, s[index]);
                cur = 0;
            }
        }
        // 最后一个数字,由于遇不到下一个运算符,所以要手动入栈
        push(numbers, ops, cur, '+');
        // 计算这一对括号内的表达式
        return compute(numbers, ops);
    }

    void push(vector<int> &numbers, vector<char> &ops, int cur, char op) {
        int n = numbers.size();
        if (n == 0 || ops.back() == '+' || ops.back() == '-') {
            // 栈空或者栈顶是加减运算符,就直接放入
            numbers.push_back(cur);
            ops.push_back(op);
        } else {
            // 栈顶是乘除运算,先弹出一个数字运算后,把结果入栈
            int topNumber = numbers.back();
            char topOp = ops.back();
            if (topOp == '*') {
                numbers[n - 1] = topNumber * cur;
            } else {
                numbers[n - 1] = topNumber / cur;
            }
            ops[n - 1] = op;
        }
    }

    // 计算剩下的加减运算
    int compute(const vector<int> &numbers, const vector<char> &ops) {
        int n = numbers.size();
        int ans = numbers[0];
        for (int j = 1; j < n; j++)
            ans += ops[j - 1] == '+' ? numbers[j] : -numbers[j];
        return ans;
    }
};

int main() {
    string s = "6-4/2*(3-1)+(2+1)*(5-3*2+(4/2+2))";
    Solution solution;
    cout << solution.calculate(s);
}

394. 字符串解码

  • 含有嵌套的字符串解码,时间复杂度 O(n)
  • 从第一个右括号开始解析,从里向外解析每一对括号,解析成字符串后入栈,继续找下个右括号
#include <iostream>
#include <string>
#include <vector>
#include <stack>

using namespace std;

class Solution {
public:
    string decodeString(string s) {
        stack<char> stk;
        // 用于逆序输出栈中内容
        deque<char> deq;

        for (int i = 0; i < s.size(); ++i) {
            // 右括号前的全部入栈
            while (i < s.size() && s[i] != ']') {
                stk.emplace(s[i]);
                i++;
            }

            // 已经到字符串 s 的结尾了
            if (s[i] != ']') break;

            // 解析括号内的字符串
            string tempStr;
            while (stk.top() != '[') {
                deq.emplace_front(stk.top());
                stk.pop();
            }
            while (!deq.empty()) {
                tempStr += deq.front();
                deq.pop_front();
            }
            // 弹出 '['
            stk.pop();

            // 解析左括号前的数字,也就是括号内字符的重复次数
            int count = 0;
            while (!stk.empty() && stk.top() >= '0' && stk.top() <= '9') {
                deq.emplace_front(stk.top());
                stk.pop();
            }
            while (!deq.empty()) {
                count *= 10;
                count += deq.front() - '0';
                deq.pop_front();
            }

            // 记录重复 count 次的字符串
            string repeated;
            for (int j = 0; j < count; ++j)
                repeated.append(tempStr);

            // 重新入栈
            for (auto &c: repeated)
                stk.emplace(c);
        }

        // 全部出栈
        string res;
        deq.clear();
        while (!stk.empty()) {
            deq.emplace_front(stk.top());
            stk.pop();
        }
        while (!deq.empty()) {
            res += deq.front();
            deq.pop_front();
        }

        return res;
    }
};
  • 用两个栈分别记录左括号之前的数字,以及数字前的字符串。每次遇到右括号就把括号内重复相应次数,然后与这个数字之前的字符串拼接
class Solution {
public:
    // "abc2[a2[c]t]2[k]xyz";
    // abcacctacctkkxyz
    string decodeString(const string &s) {
        // 临时记录数字
        int multi = 0;
        // 临时记录数字前的字符串
        string str;
        stack<int> stack_multi;
        stack<string> stack_str;

        for (char c: s) {
            if (c == '[') {
                // 遇到左括号,说明左括号前的数字已经被确定,存入栈中
                stack_multi.emplace(multi);
                // 数字之前的字符串也确定了,存入栈中
                stack_str.emplace(str);
                // 清空这两个临时变量
                multi = 0;
                str.clear();
            } else if (c == ']') {
                // 取出当前括号内字符串应该重复的次数
                int cur_multi = stack_multi.top();
                stack_multi.pop();
                // 重复对应的次数后记录到tmp中
                string tmp;
                for (int i = 0; i < cur_multi; i++) tmp += str;
                // 再接到之前数字前已经出现的字符串后面
                str = stack_str.top() + tmp;
                stack_str.pop();
            } else if (c >= '0' && c <= '9') {
                // 确定重复次数
                multi = multi * 10 + (c - '0');
            } else {
                // 记录数字前的字符串,或者是括号内的字符串
                str.push_back(c);
            }
        }
        return str;
    }
};
  • 递归
#include <string>

using namespace std;

class Solution {
public:
    int where;

    string recursive(string s, int i) {
        string str;
        int multi = 0;
        while (i < s.length() && s[i] != ']') {
            if (s[i] >= '0' && s[i] <= '9') {
                // 解析重复次数
                multi = 10 * multi + s[i++] - '0';
            } else if (s[i] == '[') {
                // 递归处理下一段
                string repeatedStr = recursive(s, i + 1);
                // 重复 multi 次,并且接在 str 后面
                while (multi > 0) {
                    str += repeatedStr;
                    multi--;
                }
                i = where + 1;
            } else {
                // 解析数字前的字符串,或者括号内的字符串
                str += s[i++];
            }
        }
        where = i;
        return str;
    }

    string decodeString(string s) {
        where = 0;
        return recursive(s, 0);
    }
};
  • 递归(推荐),index++ 跳过左括号,而不是用 where + 1 去跳过
#include <string>

using namespace std;

class Solution {
public:
    // 当前处理位置的下标
    int index = 0;

    string decodeString(string s) {
        string str;
        int multi = 0;
        for (; index < s.size(); index++) {
            if (s[index] >= '0' && s[index] <= '9') {
                // 解析重复次数
                multi = 10 * multi + s[index] - '0';
            } else if (s[index] == '[') {
                // 跳过这个左括号
                index++;
                // 递归处理括号内的字符串
                string repeatedStr = decodeString(s);
                // 重复 multi 次,并且接在 str 后面
                while (multi > 0) {
                    str += repeatedStr;
                    multi--;
                }
            } else if (s[index] == ']') {
                // 结束递归,返回括号内的字符串
                break;
            } else {
                // 解析数字前的字符串,或者括号内的字符串
                str += s[index];
            }
        }
        return str;
    }
};

726. 原子的数量

  • 含有嵌套的分子式求原子数量,时间复杂度 O(n)
  • 处理过程
    • 遇到字母:解析出元素符号,以及该元素出现次数
    • 遇到左括号 (:递归处理这段括号的分子式,从左括号一直到右括号后面的数字
    • 遇到右括号 ):如果右括号后面是数字,则需要乘对应倍数
#include <string>
#include <iostream>
#include <map>

using namespace std;

class Solution {
public:
    // 分子式中处理到的下标
    int index;

    bool isNumber(char ch) {
        return ch >= '0' && ch <= '9';
    }

    bool isLowercaseLetter(char ch) {
        return ch >= 'a' && ch <= 'z';
    }

    bool isUppercaseLetter(char ch) {
        return ch >= 'A' && ch <= 'Z';
    }

    // 返回原子出现次数
    map<string, int> recursive(string &formula) {
        // 有序 map
        map<string, int> freq;

        while (index < formula.length()) {
            if (isUppercaseLetter(formula[index])) {
                // 化学元素符号由一个大写字母或者一个大写字母加若干个小写字母确定
                string atom = "";
                atom += formula[index++];
                // 先生成完整的元素符号,如果后面是小写字母就追加上去
                while (index < formula.length() && isLowercaseLetter(formula[index]))
                    atom += formula[index++];

                // 判断这个元素符号出现的次数
                int cnt = 0;
                if (index < formula.length() && isNumber(formula[index])) {
                    while (index < formula.length() && isNumber(formula[index]))
                        cnt = cnt * 10 + formula[index++] - '0';
                } else {
                    // 只出现一次
                    cnt = 1;
                }
                freq[atom] += cnt;
            } else if (formula[index] == '(') {
                index++;
                // 递归处理这段括号的分子式,从左括号一直到右括号后面的数字
                map<string, int> tempCount = recursive(formula);
                // 累加出现次数
                for (const auto &item: tempCount)
                    freq[item.first] += item.second;
                // 结束后 index 为下一个非数字的字符的下标,继续从 index 开始处理
            } else if (formula[index] == ')') {
                index++;
                // 如果右括号后面是数字,则需要乘对应倍数
                if (index < formula.length() && isNumber(formula[index])) {
                    int cnt = 0;
                    while (index < formula.length() && isNumber(formula[index]))
                        cnt = cnt * 10 + formula[index++] - '0';
                    for (auto &item: freq)
                        freq[item.first] = item.second * cnt;
                }
                // 返回这一段分子式的元素统计
                return freq;
            }
        }
        return freq;
    }

    string countOfAtoms(string formula) {
        index = 0;
        map<string, int> count = recursive(formula);
        string res;
        // 从有序 map 中生成结果字符串
        for (const auto &item: count) {
            res.append(item.first);
            if (item.second != 1)
                res.append(to_string(item.second));
        }
        return res;
    }
};

标签:index,string,递归,括号,int,嵌套,numbers,formula
From: https://www.cnblogs.com/sprinining/p/18449114

相关文章

  • Java - 13 方法的递归
    Java-13方法的递归递归必须向退出递归的条件逼近斐波那契数列当n=1,1当n=2,1当n>=3,是前两个数的和publicclassRecursion{ publicstaticvoidmain(String[]args){ Fbnqf=newFbnq(); intn=7; intres=f.num(n); if(res!=-1) System.out.p......
  • 递归_字符串匹配,最长连续序列
    1:字符串匹配题目链接:LCR137.模糊搜索验证-力扣(LeetCode)可以使用递归的方法来检查 input 是否可以匹配 article。目的是正确处理两种通配符:‘.’和‘*’的匹配规则。defis_match(article:str,input:str)->bool:ifnotinput:returnnotarticle......
  • 经典递归
    master公式所有子问题规模相同的递归才能用master公式:T(n)=a*T(n/b)+O(n^c),a、b、c为常数若log(b,a)<c,复杂度为O(n^c),log(b,a)是以b为底a的对数若log(b,a)>c,复杂度为O(n^log(b,a))若log(b,a)=c,复杂度为O(n^c*logn)T(n)=2*T(n/2)+O(n*longn),时间复杂度为O(n*(lo......
  • PbootCMS模板怎么嵌套引用其他模版文件
    模板文件嵌套引用是一种常见的做法,可以提高代码的复用性和维护性。在PbootCMS中,可以使用 {include} 标签来引用其他模板文件。下面详细介绍如何进行模板文件嵌套引用,并给出具体示例。模板文件嵌套引用在PbootCMS中,使用 {include} 标签来引用其他模板文件。语法如下:ht......
  • 基础算法--递归算法【难点、重点】
    今天我们即将要开始讲解算法中第一块儿难啃地骨头--递归了,相信有不少小伙伴都因递归而迷惑过,本文就来给大家详细的讲解一下递归到底是什么东西。让你也能瞬间将他打回原形。递归的理解在学习递归之前,我们先理解递归。什么是递归呢?从名字上看我们可以想到递进+回归两个......
  • 【递归】小q的数列
    https://ac.nowcoder.com/acm/contest/21763/1002pow(2,ans)计算的是2的ans次幂,但是pow()函数返回的是double类型的结果。由于pow()函数主要用于浮点数计算,它返回浮点数结果,而后你可能需要对该结果进行整数操作。如果不进行显式类型转换,这个浮点数结果会丢失精度,特别是在......
  • 前端零代码-技术原理:对话框嵌套和自定义按钮| uiotos致敬amis、appsmith、codewave、g
    对话框有默认标题头和脚,带有默认的取消、确定、关闭等按钮:   对话框编辑状态和运行状态UIOTOS中对话框属常见容器,内容由任意其他页面嵌套而来。如下所示:                                   ......
  • 鹏哥C语言62---第9次作业:函数递归练习
    #define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>//-------------------------------------------------------------------------------------------第九次作业 函数递归等//----------------------------------------------------------------......
  • 11918 骰子|| 深搜 递归
    解决思路 深度优先搜索(DFS):使用DFS枚举所有可能的骰子点数组合。 剪枝:在DFS过程中,如果当前点数和已经超过 sum 或者剩余骰子无法达到 sum,则剪枝。 字典序输出:由于DFS的递归顺序,天然保证了字典序输出。#include<bits/stdc++.h>#definelllonglongus......
  • 初学Java基础Day08 方法,方法的递归,方法的重载
    一,方法1.概念:        特定功能的代码块2.好处:        减少代码的冗余3.分类:1.无参数无返回值的方法2.带参数的方法3.带返回的方法4.理解:        参数是方法调用时传入的数据,返回值是方法执行完毕后返回的数据1.无参数无返回的方法//语法结......