2021-04-01 1006. 笨阶乘 | 150. 逆波兰表达式求值 | 224. 基本计算器 | 括号展开 | 227. 基本计算器 II[栈,数学表达式求值]
1006. 笨阶乘
基本思路:
- 利用一个栈存储待相加的数字。
- 减号就立马对于当前元素进行操作,每次碰到*/立马更新栈顶的元素。
- 如109/8+7-65/4+3=10*9/8+7+(-6)*5/4+3
class Solution {
public int clumsy(int N) {
// * / + -
// 每次碰到*,/立马对于栈顶的元素进行操作
LinkedList<Integer> tmp = new LinkedList<>(); // 用来存储要加在一起的数字
tmp.add(N);
int op = 0;
N--;
while(N>0){
if(op==0)
tmp.addLast(tmp.pollLast()*N);
else if(op==1)
tmp.addLast(tmp.pollLast()/N);
else if(op==2)
tmp.addLast(N);
else
tmp.addLast(-N);
op = (op+1)%4;
N--;
}
int sum = 0;
// 把tmp加在一起
for(Integer i : tmp)
sum += i;
return sum;
}
}
150. 逆波兰表达式求值
这道题目比笨阶乘简单一点,因为实际上只要每次遇到一个新的符号就对目前栈顶的两个元素进行操作即可。
class Solution {
public int evalRPN(String[] tokens) {
// 每次遇到符号,都对栈顶的两个元素进行操作
LinkedList<Integer> tmp = new LinkedList<>();
for(int i=0;i<tokens.length;i++){
// 先判断是否为运算符号
if(tokens[i].equals("+")){
int b = tmp.pollLast();
int a = tmp.pollLast();
tmp.add(a+b);
}
else if(tokens[i].equals("-")){
int b = tmp.pollLast();
int a = tmp.pollLast();
tmp.add(a-b);
}
else if(tokens[i].equals("*")){
int b = tmp.pollLast();
int a = tmp.pollLast();
tmp.add(a*b);
}
else if(tokens[i].equals("/")){
int b = tmp.pollLast();
int a = tmp.pollLast();
tmp.add(a/b);
}
else{
tmp.add(Integer.parseInt(tokens[i]));
}
}
return tmp.poll();
}
}
224. 基本计算器 | 括号展开
这里我们尝试用括号展开的方法来解决这个问题。
想法:
+(1+2-3) = 1+2-3
-(1+2-3) = -1-2+3
即,我们每次进入一个(都要记录一个外部的符号,然后内部的加法在具体操作的时候都要再乘一个外部的符号
- 每进入一个(都在栈中记录当前外部的符号
- 每出去一个)都退出去一个符号。
class Solution {
public int calculate(String s) {
char[] expr = s.toCharArray();
int i = 0;
int res = 0;
int sign = 1;
LinkedList<Integer> op = new LinkedList<>();
op.add(sign);
while(i<expr.length){
if(expr[i]==' '){
i++;
continue;
}
// 真实的符号并不等于读取到的符号
if(expr[i]=='+'){
sign = op.peekLast();
i++;
}
else if(expr[i]=='-'){
sign = -1*op.peekLast();
i++;
}
else if(expr[i]=='('){
op.addLast(sign); // 每次记录进入括号的符号
i++;
}
else if(expr[i]==')'){
op.pollLast(); // 我们这个括号的临时符号已经不用了
i++;
}
else{
// 数字
int tmpNum = 0;
while(i<expr.length && 0<= expr[i]-'0' && expr[i]-'0'<=9){
tmpNum = 10*tmpNum + expr[i] - '0';
i++;
}
res += sign*tmpNum;
System.out.println(res);
}
}
return res;
}
}
227. 基本计算器 II
利用笨阶乘的思路。
class Solution {
public int calculate(String s) {
LinkedList<Character> op = new LinkedList<>();
op.add('+');
LinkedList<Integer> num = new LinkedList<>();
char[] c = s.toCharArray();
int i=0;
while(i<c.length){
if(c[i]==' ')
i++;
else if(c[i]=='+'){
// num.add();
i++;
}
else if(c[i]=='-'){
op.addLast('-');
i++;
}
else if(c[i]=='*'){
op.addLast('*');
i++;
}
else if(c[i]=='/'){
op.addLast('/');
i++;
}
else{
int tmp = 0;
while(i<c.length && 0<=c[i]-'0' && c[i]-'0'<=9){
tmp = tmp*10 + c[i]-'0';
i++;
}
if(op.peekLast()=='-'){
num.addLast(-tmp);
op.pollLast();
}
else if(op.peekLast()=='*'){
num.addLast(num.pollLast()*tmp);
op.pollLast();
}
else if(op.peekLast()=='/'){
num.addLast(num.pollLast()/tmp);
op.pollLast();
}
else
num.addLast(tmp);
}
}
// 最后把所有num中的数字加起来
int sum=0;
for(Integer tmp : num)
sum+=tmp;
return sum;
}
}
一般情况
class Solution {
// 使用 map 维护一个运算符优先级
// 这里的优先级划分按照「数学」进行划分即可
Map<Character, Integer> map = new HashMap<>(){{
put('-', 1);
put('+', 1);
put('*', 2);
put('/', 2);
put('%', 2);
put('^', 3);
}};
public int calculate(String s) {
// 将所有的空格去掉,并将 (- 替换为 (0-,(+ 替换为 (0+
// 当然这里也可以不预处理,而是放到循环里面去做判断
s = s.replaceAll(" ", "");
s = s.replaceAll("\\(-", "(0-");
s = s.replaceAll("\\(\\+", "(0+");
char[] cs = s.toCharArray();
int n = s.length();
// 存放所有的数字
Deque<Integer> nums = new ArrayDeque<>();
// 为了防止第一个数为负数,先往 nums 加个 0
nums.addLast(0);
// 存放所有「非数字以外」的操作
Deque<Character> ops = new ArrayDeque<>();
for (int i = 0; i < n; i++) {
char c = cs[i];
if (c == '(') {
ops.addLast(c);
} else if (c == ')') {
// 计算到最近一个左括号为止
while (!ops.isEmpty()) {
if (ops.peekLast() != '(') {
calc(nums, ops);
} else {
ops.pollLast();
break;
}
}
} else {
if (isNumber(c)) {
int u = 0;
int j = i;
// 将从 i 位置开始后面的连续数字整体取出,加入 nums
while (j < n && isNumber(cs[j])) u = u * 10 + (cs[j++] - '0');
nums.addLast(u);
i = j - 1;
} else {
// 有一个新操作要入栈时,先把栈内可以算的都算了
// 只有满足「栈内运算符」比「当前运算符」优先级高/同等,才进行运算
// 如果+-(1)遇到*/法(2),先计算*/
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(Deque<Integer> nums, Deque<Character> ops) {
if (nums.isEmpty() || nums.size() < 2) return;
if (ops.isEmpty()) return;
int b = nums.pollLast(), a = nums.pollLast();
char op = ops.pollLast();
int ans = 0;
if (op == '+') ans = a + b;
else if (op == '-') ans = a - b;
else if (op == '*') ans = a * b;
else if (op == '/') ans = a / b;
else if (op == '^') ans = (int)Math.pow(a, b);
else if (op == '%') ans = a % b;
nums.addLast(ans);
}
boolean isNumber(char c) {
return Character.isDigit(c);
}
}