计算器问题lc224

[toc]

计算器 lc224

题目描述

给定一个包含正整数、加(+)、减(-)、乘(*)、除(/)的算数表达式(括号除外),计算其结果。

表达式仅包含非负整数,+, - ,*,/ 四种运算符和空格 。 整数除法仅保留整数部分。

示例 1:

输入: "3+2*2"
输出: 7
示例 2:

输入: " 3/2 "
输出: 1
示例 3:

输入: " 3+5 / 2 "
输出: 5
说明:

你可以假设所给定的表达式都是有效的。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/calculator-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

前中后缀表达式。研究。

解决方法

1.分级运算

利用1个栈

4个队列:因为只有两种运算,乘除和加减,所以先算乘除再算加减。

执行用时:20 ms, 在所有 C++ 提交中击败了53.67%的用户

内存消耗:10.2 MB, 在所有 C++ 提交中击败了19.18%的用户

notice:给的案例有

" 3+5 / 2 "
所以遇到空格应该跳过去
        stack<int> tmpnum;//存数字,将字符串数字转成数字
        queue<int> num; //乘除的数字和符号
        queue<int> fuhao;

        queue<int> fnum;//存加减的数字和符号
        queue<int> ffuhao;
class Solution {
public:
    int calculate(string s) {
        stack<int> tmpnum;
        queue<int> num;
        queue<int> fuhao;

        queue<int> fnum;
        queue<int> ffuhao;
        // res = 0;
        int extnum=0;
        s = s+"+";
        for(int i=0;i<s.length();i++){
            extnum=0;
            if (s[i]>='0' && s[i]<='9'){
                tmpnum.push(s[i]);
            }else if(s[i]==' '){
                continue;
            }
            else{
                int j=0;
                while(!tmpnum.empty()){
                    extnum+=(tmpnum.top()-'0')*(pow(10,j));
                    j+=1;
                    tmpnum.pop();
                }
                // cout<<extnum<<endl;
                if (s[i]=='*' || s[i]=='/'){
                    num.push(extnum);
                    fuhao.push(s[i]);
                }else{//如果是+or-且之前不为空
                    int s1num = extnum;
                    if(!fuhao.empty()){
                        num.push(s1num);
                        s1num=num.front();
                        num.pop();
                        while(!fuhao.empty()){
                            int a = num.front();
                            char b=fuhao.front();
                            if(b=='*'){
                                s1num*=a;
                            }else{
                                s1num/=a;
                            }   
                            num.pop();
                            fuhao.pop();
                        }
                    }
                    // cout<<s1num<<endl;

                    fnum.push(s1num);
                    ffuhao.push(s[i]);
                }
            }
        }
        int res = fnum.front();
        fnum.pop();
        // cout<<extnum<<endl;
        while(!fnum.empty()){
            int a = fnum.front();
            char b=ffuhao.front();
            
            if(b=='+'){
                res+=a;
            }else{
                res-=a;
            }   
            fnum.pop();
            ffuhao.pop();
        }
        // cout<<"sda"<<endl;
        // cout<<res<<endl;
        return res;
    }
};
2. 知识点-字符串转整数

1)atoi和stoi

头文件都是#include<cstring>
atoi()的参数是 const char* ,因此对于一个字符串str我们必须调用 c_str()的方法把这个string转换成 const char*类型的,而stoi()的参数是const string*,不需要转化为 const char*;

stoi()会做范围检查,默认范围是在int的范围内的,如果超出范围的话则会runtime error!atoi()不会做范围检查,如果超出范围的话,超出上界,则输出上界,超出下界,则输出下界;

2)用栈,直接确定每一位

                while(!tmpnum.empty()){
                    extnum+=(tmpnum.top()-'0')*(pow(10,j));
                    j+=1;
                    tmpnum.pop();
                }

3)从头开始计算

string s = "458";

int n = 0;
for (int i = 0; i < s.size(); i++) {
    char c = s[i];
    n = 10 * n + (c - '0');
}
// n 现在就等于 458

作者:labuladong
链接:https://leetcode-cn.com/problems/basic-calculator-ii/solution/chai-jie-fu-za-wen-ti-shi-xian-yi-ge-wan-zheng-ji-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这个还是很简单的吧,老套路了。但是即便这么简单,依然有坑:(c - '0')的这个括号不能省略,否则可能造成整型溢出。

因为变量c是一个 ASCII 码,如果不加括号就会先加后减,想象一下s如果接近 INT_MAX,就会溢出。所以用括号保证先减后加才行。

作者:labuladong
链接:https://leetcode-cn.com/problems/basic-calculator-ii/solution/chai-jie-fu-za-wen-ti-shi-xian-yi-ge-wan-zheng-ji-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

新思路

1.加减法,可以通过都是加法,转换减法为负数实现。(c++ INT_MIN 忽略符号表示成正数好像会溢出)

2.乘除法思路,乘除取出栈中前一个数字运算再放进去。

3.处理空格。

4.括号。【遇到‘(’开始递归,遇到‘)’结束递归。】

本文借实现计算器的问题,主要想表达的是一种处理复杂问题的思路。

我们首先从字符串转数字这个简单问题开始,进而处理只包含加减法的算式,进而处理包含加减乘除四则运算的算式,进而处理空格字符,进而处理包含括号的算式。

可见,对于一些比较困难的问题,其解法并不是一蹴而就的,而是步步推进,螺旋上升的。如果一开始给你原题,你不会做,甚至看不懂答案,都很正常,关键在于我们自己如何简化问题,如何以退为进。

退而求其次是一种很聪明策略。你想想啊,假设这是一道***,你不会实现这个计算器,但是你写了字符串转整数的算法并指出了容易溢出的陷阱,那起码可以得 20 分吧;如果你能够处理加减法,那可以得 40 分吧;如果你能处理加减乘除四则运算,那起码够 70 分了;再加上处理空格字符,80 有了吧。我就是不会处理括号,那就算了,80 已经很 OK 了好不好。

作者:labuladong
链接:https://leetcode-cn.com/problems/basic-calculator-ii/solution/chai-jie-fu-za-wen-ti-shi-xian-yi-ge-wan-zheng-ji-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论中:

https://leetcode-cn.com/problems/basic-calculator-ii/solution/chai-jie-fu-za-wen-ti-shi-xian-yi-ge-wan-zheng-ji-/330884

lc224

执行用时:80 ms, 在所有 C++ 提交中击败了14.17%的用户

内存消耗:280.7 MB, 在所有 C++ 提交中击败了10.88%的用户

class Solution {
public:
    int calculate(string s) {
        int begin = 0;
        return calHelper(s,begin);
    }
    int calHelper(string s,int& i){//这里传的是引用
        char operation = '+';
        stack<int> nums;
        int num=0;
        int res=0;
        for(i;i<s.size();i++){
            if(s[i]>='0' && s[i]<='9'){
                num=num*10 + (s[i]-'0');
            }
            // cout<<num<<endl;
            if(s[i]=='('){//递归
                num=calHelper(s,++i);//从i的下一个计算,进入递归
                i++;//计算完,i指向‘)’,需要再++,)之后肯定不是数字,但可能是符号和)
            }
            if(i>=s.size()-1 || ((s[i]<'0'||s[i]>'9')&&s[i]!=' ')){
                int pre=0;
                switch(operation){
                    case '+':nums.push(num);
                        break;
                    case '-':nums.push(-num);
                        break;
                    case '*':
                        pre = nums.top();
                        nums.pop();
                        nums.push(pre*num);
                        break;
                    case '/':
                        pre = nums.top();
                        nums.pop();
                        nums.push(pre/num);
                        break;
                }
                operation = s[i];
                num = 0;
            }
            if(s[i]==')'){
                break;//返回递归
            }
        }
        while(!nums.empty()){
            res+=nums.top();
            nums.pop();
        }
        return res;

    }
};

值得注意的地方:

https://leetcode-cn.com/problems/basic-calculator-ii/solution/chai-jie-fu-za-wen-ti-shi-xian-yi-ge-wan-zheng-ji-/620683
int calHelper(string s, int& i) 这一句中 i 前边不加 & 为什么结果会错误?
c++写法这里有个坑,就是不能用char c = s[i],因为当进入递归之后退出来,i指向‘)’,如果用变量c代替的话,会出现当前c还是之前的‘(’,会造成逻辑混乱,而实时的用s[i]则能够走正确逻辑,同时switch那段需要放到判断‘(’的后面,从而使得跳回现在函数栈时,正确判断之后该怎么走。 总体来说,就是按照层主的代码写,没有问题,重点在于实时更新位置i,
加&是把原来的传值改为传引用,也就是对i的改变就是对原始对象的改变,不加&的话,当退出递归调用,s[i] 指向的还是原来进入递归的条件,也就是‘(’
https://leetcode-cn.com/problems/basic-calculator-ii/solution/chai-jie-fu-za-wen-ti-shi-xian-yi-ge-wan-zheng-ji-/684160
if (((s[i] < '0' || s[i] > '9') && s[i] != ' ') || i >= s.size() - 1) 
这个部分是不是需要换下顺序,因为当最后一个字符是)时,递归结束,i++就超出索引了

if (i >= s.size() - 1||((s[i] < '0' || s[i] > '9') && s[i] != ' ') ) 
if (i >= s.size() || s[i] == ')')
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352