IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> LeetCode 基本计算器 224. 227. follow up 394 -> 正文阅读

[数据结构与算法]LeetCode 基本计算器 224. 227. follow up 394

224.基本计算器

题目描述

给定一个字符串表达式s,计算并返回它的值。s只包含+-(),数字,空格。

+不用用作一元运算(比如+1+(2+3)是无效的);-可以用作一元运算(比如-1-(2+3)是有效的)。

思路1

自己的思路。双栈,一个操作符栈,一个操作数栈。比较关键的点在于,在什么时候需要执行一次实际的运算?

  • 在当前获取到一个数字,并且存在至少一个操作符时,需要运算。
  • 在当前字符是)时,说明括号内的已经计算完毕,需要和前一个操作数进行计算

为了方便的处理前方不存在第一个操作数的情况,我们用一个int变量实时保存当前运算的结果。

class Solution {
    public int calculate(String s) {
        Deque<Character> opStack = new LinkedList<>();
        Deque<Integer> numStack = new LinkedList<>();
        int sum = 0; // 保存当前的运算结果
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == ' ') continue;
            if (c == '(') {
                opStack.push('(');
                numStack.push(sum); // 把当前的运算结果暂存到操作数栈
                sum = 0; // 清零
            } else if (c == ')') {
                opStack.pop(); // 把 ( 弹出
                int a = numStack.isEmpty() ? 0 : numStack.pop();
                char op = opStack.isEmpty() ? '+' : opStack.pop();
                sum = calc(a, sum, op);
            } else if (c == '+' || c == '-') {
                opStack.push(c);
            } else if (isDigit(c)) {
                int num = 0;
                int j = i;
                while (j < s.length() && isDigit(s.charAt(j))) {
                    num = num * 10 + s.charAt(j) - '0';
                    j++;
                }
                i = j - 1;
                if (opStack.isEmpty() || opStack.peek() == '(') sum = num;
                else sum = calc(sum, num, opStack.pop());
            }
        }
        return sum;
    }

    private int calc(int a, int b, char op) {
        if (op == '+') return a + b;
        return a - b;
    }

    private boolean isDigit(char c) {
        return c >= '0' && c <= '9';
    }
}

这个思路和之前做过的一道题目很类似:394.字符串解码

思路2

由于只存在+-,我们考虑可以将括号进行展开。表达式中,除了第一个数字,其余每一个数字的前方,都一定会跟随一个+或者-。我们只需要维护,当前的符号是还是即可。

而一对括号()的出现,可能会改变括号内的运算符,所以,每当出现(时,我们就将当前的运算符压入栈,括号内部的运算符,都需要和栈顶的运算符做一个操作即可。

class Solution {
    public int calculate(String s) {
        Deque<Integer> ops = new LinkedList<>();
        int res = 0;
        int sign = 1; // 当前符号为+
        ops.push(1); // 先压入一个+号
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == ' ') continue;
            if (c == '+') sign = ops.peek();
            else if (c == '-') sign = -ops.peek(); // 和栈顶符号做一下运算
            else if (c == '(') ops.push(sign); // 压入当前符号
            else if (c == ')') ops.pop(); // 前一个(跟随的符号, 可以弹出栈了
            else if (isDigit(c)) {
                int num = 0;
                int j = i;
                while (j < s.length() && isDigit(s.charAt(j))) {
                    num = num * 10 + s.charAt(j) - '0';
                    j++;
                }
                i = j - 1;
                res += sign * num; // 括号展开直接依次计算
            }
        }
        return res;
    }

    private boolean isDigit(char c) {
        return c >= '0' && c <= '9';
    }
}

227.基本计算器II

题目描述

给定一个字符串表达式s,进行运算并求值。s中只包含+-*/和空格。

思路

双栈即可,运算符栈,只能优先级大的压优先级小的。反之需要将运算符出栈,并执行运算。

class Solution {
    public int calculate(String s) {
        Deque<Integer> nums = new LinkedList<>();
        Deque<Character> ops = new LinkedList<>();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == ' ') continue;
            if (isDigit(c)) {
                int j = i;
                int num = 0;
                while (j < s.length() && isDigit(s.charAt(j))) {
                    num = num * 10 + s.charAt(j) - '0';
                    j++;
                }
                i = j - 1;
                nums.push(num);
            } else {
                while (!ops.isEmpty() && getPriority(c) <= getPriority(ops.peek())) {
                    int b = nums.pop();
                    int a = nums.pop();
                    nums.push(calc(a, b, ops.pop()));
                }
                ops.push(c);
            }
        }
        while (!ops.isEmpty()) {
            int b = nums.pop();
            int a = nums.pop();
            nums.push(calc(a, b, ops.pop()));
        }
        return nums.pop();
    }

    private int calc(int a, int b, char c) {
        switch(c) {
            case '*' : return a * b;
            case '/' : return a / b;
            case '+' : return a + b;
            default : return a - b;
        }
    }

    private int getPriority(char c) {
        if (c == '*' || c == '/') return 2;
        return 1;
    }

    private boolean isDigit(char c) {
        return c >= '0' && c <= '9';
    }
}

对比可以发现,两种计算器的题目,做法有一些区别。
第一题是用一个变量实时保存结果(对于解394这样的题很有用),而第二题则没有进行实时计算(经典的表达式求值的做法,需要考虑运算符优先级)。

follow up

394.字符串解码

题目描述

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

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

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

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

样例

输入:s = “3[a]2[bc]”
输出:“aaabcbc”

思路

主要是需要用一个变量来保存当前已经拼接得到的字符串,然后每当遇到一个数字k,都会有k[。此时需要将先前拼接得到的字符串进行暂存,然后对[] 内的字符串处理完毕后,重复k次,拼接到先前的字符串上。使用StringBuilder 来避免String对象的频繁创建。

class Solution {
    public String decodeString(String s) {
        Deque<Integer> repeats = new LinkedList<>(); // 重复次数
        Deque<StringBuilder> strings = new LinkedList<>(); // 暂存的字符串
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (isDigit(c)) {
                int num = 0;
                int j = i;
                while (j < s.length() && isDigit(s.charAt(j))) {
                    num = num * 10 + s.charAt(j) - '0';
                    j++;
                }
                i = j - 1;
                strings.push(sb);
                repeats.push(num);
                sb = new StringBuilder();
            } else if (c == '[') continue;
            else if(c == ']') {
                StringBuilder temp = strings.pop();
                int r = repeats.pop();
                for (int j = 0; j < r; j++) temp.append(sb);
                sb = temp;
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    private boolean isDigit(char c) {
        return c >= '0' && c <= '9';
    }
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-06-26 17:03:41  更:2022-06-26 17:05:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 18:58:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码