LeetCode 逆波兰表达式
逆波兰表达式是一道非常经典的题目,算到现在因该是第四次见他了
对于这道题
- 两个整数之间的除法总是 向零截断 。
- 表达式中不含除零运算。
- 输入是一个根据逆波兰表示法表示的算术表达式
也就是说我们不需要担心其他的异常状态,只需要做好表达式的计算工作就好。那我们只需要分析好逆波兰表达式的原理就可以了。
这里引用卡哥的说法
逆波兰表达式:是一种后缀表达式,所谓后缀就是指运算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
-
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
-
适合用栈操作运算:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<long long> s;//官方修改数据了,所以这里要用longlong
//由于这道题的性质,我们不需要担心其他异常,只需要专心计算就好
for(int i=0;i<tokens.size();i++){//
if(tokens[i]=="+"||tokens[i]=="-"||tokens[i]=="*"||tokens[i]=="/"){
long long num1=s.top();
s.pop();
long long num2=s.top();
s.pop();
if(tokens[i]=="+")s.push(num1+num2);//注意这里的顺序捏,是nums2对nums1做加减乘除运算,一定要nuns2在前面
if(tokens[i]=="-")s.push(num2-num1);
if(tokens[i]=="*")s.push(num1*num2);
if(tokens[i]=="/")s.push(num2/num1);
}else{
s.push(stoll(tokens[i]));//这里stoll是直接将字符串转化为longlong 对于这道题的处理十分方便
}
}
int result =s.top();
s.pop();
return result;
}
};
LeetCode 滑动窗口求最大值
这道题我最开始想用priority_queue,但是我们的窗口是移动的,我们无法保证我们pop出去的元素是我们希望的元素。
但实际上其实priority_queue也是可以的,但是我们存储时需要多存储元素的索引
class Solution {
public:
// 定义一个函数,用于找到每个滑动窗口中的最大值
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
// 获取输入数组的长度
int n = nums.size();
// 定义一个优先队列(最大堆),存储元素及其索引
priority_queue<pair<int, int>> q;
// 初始化优先队列,将前k个元素加入队列
for (int i = 0; i < k; ++i) {
q.emplace(nums[i], i); // 元组的第一个元素是数值,第二个元素是索引
}
// 定义一个向量,用于存储结果
vector<int> ans = {q.top().first}; // 最大值是队列的顶部元素
// 遍历剩余的元素
for (int i = k; i < n; ++i) {
q.emplace(nums[i], i); // 将新元素加入队列
// 移除不在当前窗口内的元素
while (q.top().second <= i - k) {
q.pop(); // 移除队列顶部元素
}
ans.push_back(q.top().first); // 将当前窗口的最大值加入结果向量
}
return ans; // 返回结果向量
}
};
下面是卡哥的单调队列
class Solution {
private:
class MyQueue { //单调队列(从大到小)
public:
deque<int> que; // 使用deque来实现单调队列
// 每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
// 同时pop之前判断队列当前是否为空。
void pop(int value) {
if (!que.empty() && value == que.front()) {
que.pop_front();
}
}
// 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
// 这样就保持了队列里的数值是单调从大到小的了。
void push(int value) {
while (!que.empty() && value > que.back()) {
que.pop_back();
}
que.push_back(value);
}
// 查询当前队列里的最大值 直接返回队列前端也就是front就可以了。
int front() {
return que.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
MyQueue que;
vector<int> result;
for (int i = 0; i < k; i++) { // 先将前k的元素放进队列
que.push(nums[i]);
}
result.push_back(que.front()); // result 记录前k的元素的最大值
for (int i = k; i < nums.size(); i++) {
que.pop(nums[i - k]); // 滑动窗口移除最前面元素
que.push(nums[i]); // 滑动窗口前加入最后面的元素
result.push_back(que.front()); // 记录对应的最大值
}
return result;
}
};
类似桶的写法,有种暴力的感觉
class Solution {
public:
// 定义一个方法,用于找出数组中出现频率最高的k个元素
vector<int> topKFrequent(vector<int>& nums, int k) {
// 使用哈希表记录每个元素的出现次数
unordered_map<int, int> hash;
for (int i = 0; i < nums.size(); i++) {
// 将数组中的元素作为键,出现次数作为值
int a = nums[i];
hash[a]++;
}
// 使用优先队列(最大堆)来存储元素及其频率
priority_queue<pair<int, int>> pq;
// 遍历哈希表,将元素及其频率放入优先队列中
for (auto it : hash) {
pq.push({it.second, it.first});
}
/* for (auto it=hash.begin();it!=hash.end();it++) {
pq.push({it->second, it->first});
}*/
// 存储结果的向量
vector<int> res;
// 循环k次,每次取出优先队列中频率最高的元素
while (k--) {
res.push_back(pq.top().second); // 取出频率最高的元素
pq.pop(); // 从优先队列中移除该元素
}
// 返回出现频率最高的k个元素
return res;
}
};
卡哥用堆的写法
class Solution {
public:
// 小顶堆
class mycomparison {
public:
bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
return lhs.second > rhs.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k) {
// 要统计元素出现频率
unordered_map<int, int> map; // map<nums[i],对应出现的次数>
for (int i = 0; i < nums.size(); i++) {
map[nums[i]]++;
}
// 对频率排序
// 定义一个小顶堆,大小为k
priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;
// 用固定大小为k的小顶堆,扫面所有频率的数值
for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) {
pri_que.push(*it);
if (pri_que.size() > k) { // 如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
pri_que.pop();
}
}
// 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
vector<int> result(k);
for (int i = k - 1; i >= 0; i--) {
result[i] = pri_que.top().first;
pri_que.pop();
}
return result;
}
};