面试题 16.26. 计算器
给定一个包含正整数、加(+)、减(-)、乘(*)、除(/)的算数表达式(括号除外),计算其结果。
表达式仅包含非负整数,+, - ,*,/ 四种运算符和空格 。 整数除法仅保留整数部分。
示例 1:
输入: “3+2*2”
输出: 7
示例 2:
输入: " 3/2 "
输出: 1
示例 3:
输入: " 3+5 / 2 "
输出: 5
说明:
你可以假设所给定的表达式都是有效的。
请不要使用内置的库函数 eval。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/calculator-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解法:
法一:双栈传统做法
创建俩栈,分别存放字符串中的数字和运算符。
如果想从左到右顺着算,则遍历字符串需要从字符串末尾往前遍历(栈的先进后出原理),否则需要注意提取的内容。
代码不再做演示。
法二:女少 女少 口苗 法
这种解法有点巧妙,我是借鉴力扣上别人的解法的,他没怎么解释,我看过后摸索清楚了。
妙点:
- 只需创建一个栈存储数值。
- 在第一个数前添加 “+” 即: +3 - 2 * 2
- 利用运算符划分单位或多位的数值
- 遇到 “-” 取反值压栈
这是初始状态:
这是遇到 “*” 乘号 或 除号 的时候:
剩下的我在代码中解释了 ↓↓↓
还不懂的佳人们可以自己画图演示哈
class Solution {
public:
int calculate(string s) {
stack<int> st;
int num = 0; //存储遇到下一个运算符前的数值
char c = '+'; //默认第一个的数前是 + 号
for(int i=0; i<=s.length(); i++){ // i == s.length()时不会报s[i]越界错误,因此时 s[i] == '\0'。
//需要等于的原因是为了不要遗漏push最后一个值
if(isdigit(s[i])){
//遇到下一个运算符前,算出真实数值
num = num*10 + (s[i] - '0');
}
else if(isspace(s[i])) continue; //处理空格情况
else{
// 此时的c其实是上一个运算符,并不是此次的运算符
switch(c){
case '+': st.push(num);break;
case '-': st.push(-num);break; // 妙的一步,遇到减号直接取反
case '*': {
// st.top()的值其实是上次符号'x'的前一个值,把这个值与'x'的后一个值相乘后压栈
num *= st.top(); st.pop();
st.push(num);
break;
}
case '/': {
//同上,但需注意除数与被除数的顺序
num = st.top() / num; st.pop();
st.push(num);
break;
}
}
//遇到了运算符,终止首位*10的取值
num = 0;
//存储当前运算符
c = s[i];
}
}
//遍历栈计算最终值
int res = 0;
while(!st.empty()){
//这里就体现出了负号取反的优势了
res += st.top();
st.pop();
}
return res;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(n)
739. 每日温度
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/daily-temperatures
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
这是我第一次遇到单调栈解法的题目。
我的理解就是,栈底的值(下标)所对应原来数组中的值,在遍历当前元素之前,必是最大的。
因为要取下标差值,所以入栈的都是元素的下标值。
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& T) {
stack<int> st;
int len = T.size();
vector<int> res(len, 0);
for(int i=0; i<len; i++){
//下面这步目的是为了保持栈顶下标原来的值始终是最大的
while(!st.empty() && T[st.top()] < T[i]){
int idx = st.top(); st.pop();
res[idx] = i - idx; //取差值
}
st.push(i);
}
return res;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(n)