惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog RSS Feed
K
Kaspersky official blog
Forbes - Security
Forbes - Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Proofpoint News Feed
G
GRAHAM CLULEY
V
Vulnerabilities – Threatpost
Security Latest
Security Latest
Scott Helme
Scott Helme
S
Securelist
美团技术团队
T
Threat Research - Cisco Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
SegmentFault 最新的问题
W
WeLiveSecurity
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Apple Machine Learning Research
Apple Machine Learning Research
The Cloudflare Blog
AI
AI
L
Lohrmann on Cybersecurity
S
Security Affairs
Cloudbric
Cloudbric
SecWiki News
SecWiki News
爱范儿
爱范儿
雷峰网
雷峰网
Engineering at Meta
Engineering at Meta
C
Cyber Attacks, Cyber Crime and Cyber Security
大猫的无限游戏
大猫的无限游戏
N
News and Events Feed by Topic
I
InfoQ
S
Secure Thoughts
AWS News Blog
AWS News Blog
A
About on SuperTechFans
Schneier on Security
Schneier on Security
酷 壳 – CoolShell
酷 壳 – CoolShell
The Last Watchdog
The Last Watchdog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Check Point Blog
P
Palo Alto Networks Blog
博客园 - 【当耐特】
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Google DeepMind News
Google DeepMind News
Latest news
Latest news
I
Intezer
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
V
V2EX
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
D
Docker

ImCaO's Blog

なんでもないや VuePress 2.0 中使用 Algolia DocSearch 文档搜索功能的配置 7 Years JustLaws 法律文库贡献指南 Love Story 阻止文明倒塌:Jonathan Blow 在莫斯科 DevGAMM 上的演讲 我做了一个法律文库,这可能是最简洁、便捷查询法律条文的地方 Spring Data Neo4j 开发记录 岛屿类问题的通用解法、DFS 遍历框架 When You're Gone 近况 很久以后 Spring Boot 自动配置原理 我怀念的 Webpack 核心概念 制造设备实时数据传输架构方案 暑假摸的鱼 夏至已至 CSS 选择器
基本计算器问题的双栈通用解法
宫水三叶 · 2022-02-24 · via ImCaO's Blog

题目

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。

整数除法仅保留整数部分。

示例 1:
输入:s = “(1+(4+5+2)-3)+(6+8)”
输出:23

示例 2:
输入:s = " 3+5 / 2 "
输出:5

说明

这一类题有多种变式,如 224. 基本计算器 中表达式只含有 +, -()227. 基本计算器 II 中含有 +, -, *, /772. 基本计算器 III 中含有 +,-, *, / 以及 ()。本文介绍的双栈通用解法适用于以上所有题目。

算法流程

首先创建两个栈 numsops,分别存放表达式中的数字和操作符。

然后从前往后遍历表达式,对于遍历到的字符做分类讨论。

  • 空格:跳过
  • (:加入到 ops 中,等待与之匹配的 )
  • ):使用现有的 numsops 进行计算,直到遇到左边最近的一个左括号为止,计算结果放回到 nums
  • 数字 : 从当前位置开始继续往后取,将整一个连续数字整体取出,加入 nums
  • 运算符:加入到 ops 中。在加入之前先把栈内可以算的都算掉(只有「栈内运算符」比「当前运算符」优先级高/同等,才进行运算),使用现有的 numsops 进行计算,直到没有操作或者遇到左括号,计算结果放到 nums

其中, 只有「栈内运算符」比「当前运算符」优先级高/同等,才进行运算 的意思是:

假设当前已经扫描到了 2 + 1(此时栈内的操作为 + )。

  • 如果后面出现的 + 2 或者 - 1 的话,满足「栈内运算符」比「当前运算符」优先级高/同等,可以将 2 + 1 算掉,把结果放到 nums 中;
  • 如果后面出现的是 * 2 或者 / 1 的话,不满足「栈内运算符」比「当前运算符」优先级高/同等,这时候不能计算 2 + 1

一些细节:

  • 由于第一个数可能是负数,为了减少边界判断。一个小技巧是先往 nums 添加一个 0
  • 为防止 () 内出现的首个字符为运算符,将所有的空格去掉,并将 (- 替换为 (0-(+ 替换为 (0+(当然也可以不进行这样的预处理,将这个处理逻辑放到循环里去做)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
class Solution {
public int calculate(String s) {

Map<Character, Integer> map = new HashMap<>();
map.put('-', 1);
map.put('+', 1);
map.put('*', 2);
map.put('/', 2);
ArrayDeque<Integer> nums = new ArrayDeque<>();
ArrayDeque<Character> ops = new ArrayDeque<>();

nums.addLast(0);

s = s.replace(" ", "");
char[] cs = s.toCharArray();
for (int i = 0; i < cs.length; i++) {
char c = cs[i];
if (c == '(') {
ops.addLast(c);
} else if (c == ')') {

while (ops.peekLast() != '(') {
calc(nums, ops);
}

ops.pollLast();
} else if (isNum(c)) {
int sum = 0;
int j = i;

while (j < cs.length && isNum(cs[j])) {
sum = sum * 10 + (cs[j] - '0');
j++;
}
nums.addLast(sum);

i = j - 1;
} else {

if (i > 0 && cs[i - 1] == '(') {
nums.addLast(0);
}

while (!ops.isEmpty() && ops.peekLast() != '(') {
char prev = ops.peekLast();

if (map.get(prev) >= map.get(c)) {
calc(nums, ops);
} else {
break;
}
}

ops.addLast(c);
}
}

while (!ops.isEmpty()) {
calc(nums, ops);
}
return nums.peekLast();
}


void calc(ArrayDeque<Integer> nums, ArrayDeque<Character> ops) {

if (nums.size() < 2)
return;
if (ops.isEmpty())
return;

int b = nums.pollLast();
int a = nums.pollLast();

char o = ops.pollLast();
int c = 0;
if (o == '-') {
c = a - b;
} else if (o == '+') {
c = a + b;
} else if (o == '*') {
c = a * b;
} else {
c = a / b;
}

nums.addLast(c);
}

boolean isNum(char c) {
return Character.isDigit(c);
}
}

版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 ImCaO's Blog