227. 基本计算器 II
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1] 的范围内。
注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。
示例 1:
输入:s = “3+2*2”
输出:7
示例 2:
输入:s = " 3/2 "
输出:1
示例 3:
输入:s = " 3+5 / 2 "
输出:5
提示:
1
<
=
s
.
l
e
n
g
t
h
<
=
3
∗
1
0
5
1 <= s.length <= 3 * 10^5
1<=s.length<=3∗105
s 由整数和算符 (‘+’, ‘-’, ‘*’, ‘/’) 组成,中间由一些空格隔开
s 表示一个 有效表达式
表达式中的所有整数都是非负整数,且在范围
[
0
,
2
31
−
1
]
[0, 2^{31} - 1]
[0,231−1] 内
题目数据保证答案是一个 32-bit 整数
#include <string>
#include <map>
#include <stack>
using namespace std;
class Solution
{
int calOneOp(int firstNum, int secondNum, char op)
{
int res = 0;
switch (op)
{
case '+':
res = firstNum + secondNum;
break;
case '-':
res = firstNum - secondNum;
break;
case '*':
res = firstNum * secondNum;
break;
case '/':
res = firstNum / secondNum;
break;
default:
break;
}
return res;
}
public:
int calculate(string s)
{
map<char, int> opPriority;
opPriority['+'] = 0;
opPriority['-'] = 0;
opPriority['*'] = 1;
opPriority['/'] = 1;
stack<int> nums;
stack<char> ops;
for (int i = 0; i < s.size();)
{
if (s[i] >= '0' && s[i] <= '9')
{
int tmp = 0;
while (s[i] >= '0' && s[i] <= '9')
{
tmp = s[i] - '0' + tmp * 10;
i++;
}
nums.emplace(tmp);
}
else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/')
{
if (ops.empty() || opPriority[s[i]] > opPriority[ops.top()])
{
ops.push(s[i]);
}
else
{
while (!ops.empty() && !(opPriority[s[i]] > opPriority[ops.top()]))
{
int firstNum, secondNum;
if (!nums.empty())
{
secondNum = nums.top();
nums.pop();
}
else
{
return -1;
}
if (!nums.empty())
{
firstNum = nums.top();
nums.pop();
}
nums.push(calOneOp(firstNum, secondNum, ops.top()));
ops.pop();
}
ops.push(s[i]);
}
i++;
}
else if (s[i] == ' ')
{
i++;
}
else
{
return -1;
}
}
while (!ops.empty())
{
int firstNum, secondNum;
if (!nums.empty())
{
secondNum = nums.top();
nums.pop();
}
else
{
return -1;
}
if (!nums.empty())
{
firstNum = nums.top();
nums.pop();
}
nums.push(calOneOp(firstNum, secondNum, ops.top()));
ops.pop();
}
return nums.top();
}
};
int main()
{
string compStr = "3/2";
Solution sol;
int res = sol.calculate(compStr);
return 0;
}
里面有几个需要注意的点,比如会超范围:
-
为了防止超范围,应该把tmp*10放到最后:因为根据结合性原则,表达式是从左往右计算的tmp = tmp * 10 + s[i] - ‘0’;计算过程中,s[i]是一个ASCII值(在题目数据中,是大于10的),中间结果tmp * 10+s[i]>tmp * 10+s[i] - ‘0’,但如果把tmp*10放在后面,即:tmp = s[i] - ‘0’ + tmp * 10;中间结果不会超过max(最终结果, (int)s[i])。
-
刷leco的时候,leco在运行代码前,应该是会进行静态审查的,一些不安全的代码不会运行,比如报这种错误,所以代码的异常值要进行处理,比如在使用top的时候进行判空:
295. 数据流的中位数
中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。
例如 arr = [2,3,4] 的中位数是 3 。
例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5 。
实现 MedianFinder 类:
MedianFinder() 初始化 MedianFinder 对象。
void addNum(int num) 将数据流中的整数 num 添加到数据结构中。
double findMedian() 返回到目前为止所有元素的中位数。与实际答案相差 10-5 以内的答案将被接受。
示例 1:
输入
[“MedianFinder”, “addNum”, “addNum”, “findMedian”, “addNum”, “findMedian”]
[[], [1], [2], [], [3], []]
输出
[null, null, null, 1.5, null, 2.0]
解释
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1); // arr = [1]
medianFinder.addNum(2); // arr = [1, 2]
medianFinder.findMedian(); // 返回 1.5 ((1 + 2) / 2)
medianFinder.addNum(3); // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0
提示:
−
1
0
5
<
=
n
u
m
<
=
1
0
5
-10^5 <= num <= 10^5
−105<=num<=105
在调用 findMedian 之前,数据结构中至少有一个元素
最多
5
∗
1
0
4
5 * 10^4
5∗104 次调用 addNum 和 findMedian
主要思路,就是利用两个栈,将数组拆分,来查找中位数,这就将插入的复杂度降到了O(log(n))的级别。很巧妙。
在实现最大堆的时候,less模板表示大顶堆,插入的时候返回true的时候就会停止;
greater表示小顶堆,插入的时候,返回true的时候会停止;
两个模板函数的命名,是和堆这种数据结构密切相关的。
#include <queue>
#include <iostream>
using namespace std;
class MedianFinder
{
priority_queue<int, vector<int>, less<int>> maxQue; // 大顶堆
priority_queue<int, vector<int>, greater<int>> minQue; // 小顶堆
public:
MedianFinder()
{
}
void addNum(int num)
{
if (maxQue.empty() || num <= maxQue.top())
{
maxQue.push(num);
if (maxQue.size() > minQue.size() + 1)
{
minQue.push(maxQue.top());
maxQue.pop();
}
}
else
{
minQue.push(num);
if (minQue.size() > maxQue.size())
{
maxQue.push(minQue.top());
minQue.pop();
}
}
}
double findMedian()
{
if (maxQue.empty() && minQue.empty())
return -1;
return minQue.size() == maxQue.size() ? (double)(minQue.top() + maxQue.top()) / 2 : maxQue.top();
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/
int main()
{
MedianFinder *obj = new MedianFinder();
obj->addNum(3);
double medain = obj->findMedian();
cout << medain << endl;
obj->addNum(5);
medain = obj->findMedian();
cout << medain << endl;
obj->addNum(3);
medain = obj->findMedian();
cout << medain << endl;
obj->addNum(2);
medain = obj->findMedian();
cout << medain << endl;
}
326. 3 的幂
给定一个整数,写一个函数来判断它是否是 3 的幂次方。如果是,返回 true ;否则,返回 false 。
整数 n 是 3 的幂次方需满足:存在整数 x 使得 n == 3x
示例 1:
输入:n = 27
输出:true
示例 2:
输入:n = 0
输出:false
示例 3:
输入:n = 9
输出:true
示例 4:
输入:n = 45
输出:false
提示:
− 2 31 < = n < = 2 31 − 1 -2^{31} <= n <= 2^{31} - 1 −231<=n<=231−1
进阶:你能不使用循环或者递归来完成本题吗?
#include <iostream>
using namespace std;
class Solution
{
public:
bool isPowerOfThree(int n)
{
if (n < 0)
return false;
unsigned int power_3 = 1;
unsigned int unsigned_n = n;
while (power_3 < unsigned_n)
{
power_3 *= 3;
}
if (power_3 == unsigned_n)
{
return true;
}
return false;
}
};
int main()
{
Solution sol;
bool res = sol.isPowerOfThree(27);
cout << res;
}
题解1给出了一种时间复杂度为O(1)的做法:
在题目给定的 32 位有符号整数的范围内,最大的 3 的幂为 3 19 = 11622614673 3^{19}=11622614673 319=11622614673。我们只需要判断 n 是否是 3 19 3^{19} 319 的约数即可。
class Solution {
public:
bool isPowerOfThree(int n) {
return n > 0 && 1162261467 % n == 0;
}
};
329. 矩阵中的最长递增路径
给定一个 m x n 整数矩阵 matrix ,找出其中 最长递增路径 的长度。
对于每个单元格,你可以往上,下,左,右四个方向移动。 你 不能 在 对角线 方向上移动或移动到 边界外(即不允许环绕)。
示例 1:
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/9a53090a832a49989a728b2531d23d42.png#pic_center, x_16=200x)
输入:matrix = [[9,9,4],[6,6,8],[2,1,1]]
输出:4
解释:最长递增路径为 [1, 2, 6, 9]。
示例 2:
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/92373cb0026e4275af34201ddde85efe.png#pic_center, x_16=200x)
输入:matrix = [[3,4,5],[3,2,6],[2,2,1]]
输出:4
解释:最长递增路径是 [3, 4, 5, 6]。注意不允许在对角线方向上移动。
示例 3:
输入:matrix = [[1]]
输出:1
提示:
m
=
=
m
a
t
r
i
x
.
l
e
n
g
t
h
m == matrix.length
m==matrix.length
n
=
=
m
a
t
r
i
x
[
i
]
.
l
e
n
g
t
h
n == matrix[i].length
n==matrix[i].length
1
<
=
m
,
n
<
=
200
1 <= m, n <= 200
1<=m,n<=200
0
<
=
m
a
t
r
i
x
[
i
]
[
j
]
<
=
2
31
−
1
0 <= matrix[i][j] <= 2^{31} - 1
0<=matrix[i][j]<=231−1
没有直接解题,参考了题解的代码2,采用了BFS,同时利用一个memo矩阵,来对已经搜索过的空间进行记录,防止重复计算:
class Solution
{
int direction[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
public:
int longestIncreasingPath(vector<vector<int>> &matrix)
{
if (matrix.size() == 0 || matrix[0].size() == 0)
return -1;
int res = 0;
vector<vector<int>> memo(matrix.size(), vector<int>(matrix[0].size()));
for (int i = 0; i < matrix.size(); i++)
{
for (int j = 0; j < matrix[0].size(); j++)
{
res = max(res, dfs(matrix, i, j, memo));
}
}
return res;
}
int dfs(vector<vector<int>> &matrix, int row, int column, vector<vector<int>> &memo)
{
if (memo[row][column] != 0)
{
return memo[row][column];
}
memo[row][column]++;
for (int i = 0; i < 4; i++)
{
int newRow = row + direction[i][0];
int newColumn = column + direction[i][1];
if (newRow >= 0 && newRow < matrix.size() && newColumn >= 0 && newColumn < matrix[0].size() && matrix[row][column] > matrix[newRow][newColumn])
{
memo[row][column] = max(memo[row][column], dfs(matrix, newRow, newColumn, memo) + 1);
}
}
return memo[row][column];
}
};
把矩阵看成一个有向图,从出度为0的节点开始,进行拓扑排序,最终拓扑排序的轮数就是最长路径:
class Solution
{
int direction[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
public:
int longestIncreasingPath(vector<vector<int>> &matrix)
{
vector<vector<int>> outDegree = vector<vector<int>>(matrix.size(), vector<int>(matrix[0].size(), 0));
for (int i = 0; i < matrix.size(); i++)
{
for (int j = 0; j < matrix[0].size(); j++)
{
for (int k = 0; k < 4; k++)
{
int newX = i + direction[k][0];
int newY = j + direction[k][1];
if (newX >= 0 && newX < matrix.size() && newY >= 0 && newY < matrix[0].size() && matrix[i][j] < matrix[newX][newY])
{
outDegree[i][j]++;
}
}
}
}
queue<pair<int, int>> que;
for (int i = 0; i < outDegree.size(); i++)
{
for (int j = 0; j < outDegree[0].size(); j++)
{
if (outDegree[i][j] == 0)
que.push({i, j});
}
}
int res = 0;
while (!que.empty())
{
res++;
int size = que.size();
for (int i = 0; i < size; i++)
{
int X = que.front().first;
int Y = que.front().second;
que.pop();
for (int j = 0; j < 4; j++)
{
int newX = X + direction[j][0];
int newY = Y + direction[j][1];
if (newX >= 0 && newX < matrix.size() && newY >= 0 && newY < matrix[0].size() && matrix[X][Y] > matrix[newX][newY])
{
outDegree[newX][newY]--;
if (outDegree[newX][newY] == 0)
{
que.push({newX, newY});
}
}
}
}
}
return res;
}
};