【栈】【leetcode】【中等】227. 基本计算器 II

题目:

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

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

示例:

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

来源:

227. 基本计算器 II

解题思路:栈

因为只有加减乘除且正整数,判断逻辑相对简单。

定义2个栈,一个存数字,另一个存操作符且只存+-操作符。

把第一个数字入栈,遍历后面的字符串,操作符与数字将配对出现。

  • 如果是加减号,数字入栈,操作符入栈
  • 如果是乘除号,栈顶数字与新数字计算并修改栈顶数字

最后遍历操作符的栈,按从头到尾的顺序计算加法或减法。

c代码:

使用数组实现栈,注意栈大小,注意int越界。

char *get(char *s, long *n) {
    char *p = s;
    while (*p == ' ') p++;
    *n = 0;
    while (*p >= '0' && *p <= '9') {
        *n = *n * 10 + *p - '0';
        p++;
    }
    while (*p == ' ') p++;
    return p;
}

// +-*/正整数
int calculate(char * s) {
    long num[210000];
    char opt[210000];
    int topn = -1;
    int topo = -1;

    long n = 0;
    char *p = get(s, &n);
    num[++topn] = n;
    while (*p != 0) {
        char ch = *p;
        p = get(p+1, &n);
        if (ch == '*') {
            num[topn] *= n;
        } else if (ch == '/') {
            num[topn] /= n;
        } else {
            num[++topn] = n;
            opt[++topo] = ch;
        }
    }

    long ret = num[0];
    for (int i = 0; i <= topo; i++) {
        if (opt[i] == '+') {
            ret += num[i+1];
        } else {
            ret -= num[i+1];
        }
    }
    return ret;
}

以为空间消耗很大,但从结果上看也不大。

优化思路1:

因为没有括号,所以不需大量存储空间。

当操作符数量等于2时,可以合并栈中的数字。因为此时栈中有且只有3个数,且这3个数是加减关系,所以可以且只可以合并第一个和第二个数字。

优化之后代码如下:

char *get(char *s, long *n) {
    char *p = s;
    while (*p == ' ') p++;
    *n = 0;
    while (*p >= '0' && *p <= '9') {
        *n = *n * 10 + *p - '0';
        p++;
    }
    while (*p == ' ') p++;
    return p;
}

// +-*/正整数
int calculate(char * s) {
    long num[3];
    char opt[2];
    int topn = -1;
    int topo = -1;

    long n = 0;
    char *p = get(s, &n);
    num[++topn] = n;
    while (*p != 0) {
        char ch = *p;
        p = get(p+1, &n);
        if (ch == '*') {
            num[topn] *= n;
        } else if (ch == '/') {
            num[topn] /= n;
        } else {
            num[++topn] = n;
            opt[++topo] = ch;
            if (topo == 1) {
                // 合并第一个和第二个数字
                if (opt[0] == '+') {
                    num[0] += num[1];
                } else {
                    num[0] -= num[1];
                }
                num[1] = num[2];
                topn = 1;
                opt[0] = opt[1];
                topo = 0;
            }
        }
    }

    long ret = num[0];
    for (int i = 0; i <= topo; i++) {
        if (opt[i] == '+') {
            ret += num[i+1];
        } else {
            ret -= num[i+1];
        }
    }
    return ret;
}

运行结果:

优化思路2:

上面代码依旧很复杂,为此再次优化。

优化的思路是:

1,当符号是-号时,把数字变为负数,减号就变成了加号,所以第二个栈全部是加号,没必要存在了。

2,由于第一个栈只需3个空间:一个存储之前的结果,一个存储栈顶元素,一个存储新数字,定义三个变量即可。为了去掉栈顶的指针,只需将字符串s变成0+s即可,保证指针始终指向栈顶。

优化后代码如下:

char *get(char *s, long *n) {
    char *p = s;
    while (*p == ' ') p++;
    *n = 0;
    while (*p >= '0' && *p <= '9') {
        *n = *n * 10 + *p - '0';
        p++;
    }
    while (*p == ' ') p++;
    return p;
}

int calculate(char * s) {
    long ret = 0, top = 0;

    char *p = get(s, &top); // 将第一个数字放入栈顶top
    while (*p != 0) {
        char ch = *p;
        long n = 0;
        p = get(p+1, &n);
        if (ch == '*') {
            top *= n;
        } else if (ch == '/') {
            top /= n;
        } else {
            if (ch == '-') n = 0 - n;
            ret += top;
            top = n;
        }
    }
    return ret + top;
}

文章先后修改多次,至此应该不会再修改了,除非发现其他解题思路。一件产品需要经过多次锤炼才能更加接近完美。

猜你喜欢

转载自blog.csdn.net/hbuxiaoshe/article/details/114635663
今日推荐