LeetCode 227 + Leetcode 224 基本计算器 Basic Calculator

LeetCode 227 基本计算器 II (Basic Calculator II)

题目的👍数:1704

题目的👎数:292

1、题目描述

实现一个基本的计算器来计算一个简单的字符串表达式的值。

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

示例 1:

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

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

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

2、思路与方法

这种计算器问题大多数都是用栈来解决,大部分题解利用的也是栈,不过这个题不涉及到括号的嵌套计算,其实不使用栈也是可以的,可以降低空间复杂度。

实例: 3 + 5*5/3 + 5 -3/5

比如以上例子,我们需要考虑的其实是: (3)+(5*5/3)+(5)-(3/5),也就是说用加减法将公式分块,分别计算每一块中的结果,再穿起来即可。

通过以上分析,不难想到可以使用双指针的方式,找到每段的前后索引,然后再计算中间一部分的结果即可。此外,考虑使用两个技巧来避免边界情况的判断:

1)哨兵。 在前后加上 “0+” 和 "+0"即转化为

0+3 + 5*5/3 + 5 -3/5+0

这样可以保证每段都可以遍历到

2)在计算乘除时,遍历到的乘除号要等到下一个数字才能使用,那么如何计算第一个遍历到的数字呢?我们可以初始化

int cur = 1;//这个用于保存结果
int flagForNext = 1; //这个用来判断乘除,初始为1*某个数

这样就隐式的在前面加入了 1*(…)

三、代码

class Solution {
    public int calculate(String s) {
        s = "0+" + s + "+0";
        int length = s.length();
        int res = 0;
        int start = 1;
        int end = 1;
        System.out.println(s);
        while(end < length) {
            char ch = s.charAt(start);
            int flag = ch == '+' ? 1:-1;//这个用来判断加减
            end = start+1;
            while(end < length && (s.charAt(end) != '+' && s.charAt(end) != '-')) ++end;//取出来这一段
            int cur = 1;
            int flagForNext = 1; //这个用来判断乘除,初始为1*某个数
            while(start < end) { //获取这一段的结果存到cur,这样我们就只需要在外循环考虑加减了
                start++;
                while(s.charAt(start) == ' ') {
                    ++start;
                }
                int num = 0;
                while(start < end && s.charAt(start) >= '0' && s.charAt(start) <= '9') {
                    int temp = s.charAt(start) - '0';
                    num = num * 10;
                    num += temp;
                    ++start;
                }
                if(flagForNext == 1) cur = cur * num;
                else cur = cur / num;
                while(start < end && s.charAt(start) == ' ') {
                    ++start;
                }
                if(start < end && s.charAt(start) == '/') flagForNext = 2;//改变他,下一轮迭代使用
                if(start < end && s.charAt(start) == '*') flagForNext = 1;
            } 
            res += flag*cur;
        }
        return res;
    }
}

四、复杂度

时间复杂度:双指针一重循环,时间复杂度为O(n)

空间复杂度:减少对栈的依赖,空间复杂度为O(1)

Leetcode 224:基本计算器(Basic Calculator)224. 基本计算器

题目的👍数:1718

题目的👎数:141

1、问题描述

实现一个基本的计算器来计算一个简单的字符串表达式的值。

字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格  。

示例 1:

输入: "1 + 1"
输出: 2
示例 2:

输入: " 2-1 + 2 "
输出: 3
示例 3:

输入: "(1+(4+5+2)-3)+(6+8)"
输出: 23

2、思路与方法

这个题和上个题类似,难点有所区别。上个体主要是需要对乘除法进行计算,这个题则需要考虑到括号的影响,有了括号的嵌套,例如计算(3-(3-1))时需要先计算(3-1),这个时候自然得借助栈来实现

  • 考虑栈中记录四种东西:
数字 :如果是负数,还得将'-'-3进栈
'(' :-1
'+' :-2
'-' :-3
  • 自然是当遇见 ‘)‘时出栈,其余符号时进栈,出栈时我们需要计算到上一个’(’,然后再将计算的结果进栈
  • 和上面的问题类似,使用哨兵"(" + s + ")"来保证整个s我们都会记录到

小插曲:一开始做这个题的时候想到的是负数转化成 ‘-’ 和正数的形式,方便我们用负数来表示符号,然而没有考虑到的是这种情况:

5 - (1-4)

上述的方式,括号里面出栈会使栈中变成

'5','-','-','3'

可以发现产生了两个负号,事实上如果括号嵌套进一步增加,这个负号数量也许会继续增多,因此在第一个符号出栈的时候,我们还需要一直进行出栈操作,直到栈顶不再为‘+’或者’-'为止,用flag来记录符号的变化,最终代表了这一段的结果

  • 最终栈中只会剩一个正数或者一个正数加一个负号,判断栈的size做出相应的返回即可

三、代码

修改了比较多东西导致代码相对冗长,过多的判断似乎也影响了效率。

class Solution {
    public int calculate(String s) {
        StringBuilder sb = new StringBuilder("(" + s + ")");

        //用栈解决括号的嵌套问题
        Stack<Integer> st = new Stack<>();

        //栈里面需要记录四种东西:
        //1)数字
        //2)'(' :-1
        //3)'+' :-2
        //4) '-' :-3

        int start = 0;
        while(start < sb.length()) {
            int ch = sb.charAt(start);
            if(ch == ' ') {
                ++start;
            } else if(ch >= '0' && ch <= '9') {//获取这个数字
                int cur = 0;
                while(sb.charAt(start) >= '0' && sb.charAt(start) <= '9') {
                    cur = cur * 10;
                    cur += sb.charAt(start) - '0';
                    ++start;
                }
                st.push(cur);
            } else {
                if(ch == ')') { //出栈,求得结果
                    int cur = 0;
                    while(true) {
                        int pre = st.pop();//记录加减
                        if(pre == -1) break;
                        int next = st.pop();
                        int flag = 1;
                        if(next == -3 || next == -2) {
                            flag = next == -3? -1:1;
                            while(!st.isEmpty() && (st.peek() == -3 || st.peek() == -2))
                            {
                                if(st.peek() == -3) flag*=-1;
                                st.pop();
                            }
                        }
                        cur+=pre*flag;
                        if(next == -1) break;
                    }
                    if(cur < 0) st.push(-3);
                    st.push(Math.abs(cur));
                }
                if(ch == '(') st.push(-1);
                if(ch == '+') st.push(-2);
                if(ch == '-') st.push(-3);
                ++start;
            }
        }
        if(st.size() == 2) return st.peek() * -1;
        return st.peek();
    }
}

四、复杂度

时间复杂度:仍为O(n)

空间复杂度:利用了一个栈,为O(n)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值