算法学习——LeetCode力扣栈与队列篇2
150. 逆波兰表达式求值
150. 逆波兰表达式求值 - 力扣(LeetCode)
描述
给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
注意:
- 有效的算符为 ‘+’、‘-’、‘*’ 和 ‘/’ 。
- 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
- 两个整数之间的除法总是 向零截断 。
- 表达式中不含除零运算。
- 输入是一个根据逆波兰表示法表示的算术表达式。
- 答案及所有中间计算结果可以用 32 位 整数表示。
示例
示例 1:
输入:tokens = [“2”,“1”,“+”,“3”,“*”]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入:tokens = [“4”,“13”,“5”,“/”,“+”]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:
输入:tokens = [“10”,“6”,“9”,“3”,“+”,“-11”,““,”/“,””,“17”,“+”,“5”,“+”]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
提示
1 <= tokens.length <= 104
tokens[i] 是一个算符(“+”、“-”、“*” 或 “/”),或是在范围 [-200, 200] 内的一个整数
逆波兰表达式:
逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
- 平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
- 该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
- 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
- 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
代码解析
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<long long> my_stack;
for(int i=0 ; i<tokens.size() ;i++)
{
if(tokens[i]=="+"||tokens[i]=="-"||tokens[i]=="*"||tokens[i]=="/")
{
long long tmp1 = my_stack.top();
my_stack.pop();
long long tmp2 = my_stack.top();
my_stack.pop();
// cout<<tmp2<<' '<<tmp1<<endl;
if(tokens[i] == "+")
my_stack.push( tmp2+tmp1);
else if(tokens[i] == "-")
my_stack.push( tmp2-tmp1);
else if(tokens[i] == "*")
my_stack.push(tmp2*tmp1);
else if(tokens[i] == "/")
my_stack.push(tmp2/tmp1 );
}else
my_stack.push(stoi(tokens[i]));
}
return my_stack.top();
}
};
239. 滑动窗口最大值
239. 滑动窗口最大值 - 力扣(LeetCode)
描述
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
示例 2:
输入:nums = [1], k = 1
输出:[1]
提示
- 1 <= nums.length <= 105
- -104 <= nums[i] <= 104
- 1 <= k <= nums.length
代码解析
双向队列(超时)
class Solution {
public:
int find_max(deque<int> &my_win)
{
int resuelt = INT_MIN;
for(int i=0 ; i<my_win.size() ;i++)
if(my_win[i] > resuelt) resuelt = my_win[i];
return resuelt;
}
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> resuelt;
deque<int> my_win;
if(k > nums.size()) return resuelt;
for(int i=0 ; i<k;i++)
my_win.push_back(nums[i]);
resuelt.push_back(find_max(my_win));
for(int i=k ; i<nums.size() ;i++)
{
int dele = my_win.front();
my_win.pop_front();
my_win.push_back(nums[i]);
if(nums[i] > resuelt.back())
resuelt.push_back(nums[i]);
else if(dele == resuelt.back())
resuelt.push_back(find_max(my_win));
else
resuelt.push_back(resuelt.back());
}
return resuelt;
}
};
单调队列
class Solution {
public:
class MYdeque
{
deque<int> my_deque;
public:
void pop(int value)
{
if(my_deque.empty() != 1 && value == my_deque.front())
my_deque.pop_front();
return;
}
void push(int value)
{
while(my_deque.empty() != 1 && value > my_deque.back())
{
my_deque.pop_back();
}
my_deque.push_back(value);
return;
}
int front()
{
return my_deque.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> result;
MYdeque my_deq;
for(int i=0 ; i<k ; i++)
my_deq.push(nums[i]);
result.push_back(my_deq.front());
for(int i=k; i<nums.size() ;i++)
{
my_deq.pop(nums[i-k]);
my_deq.push(nums[i]);
result.push_back(my_deq.front());
}
return result;
}
};
347. 前 K 个高频元素
347. 前 K 个高频元素 - 力扣(LeetCode)
描述
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示
- 1 <= nums.length <= 105
- k 的取值范围是 [1, 数组中不相同的元素的个数]
- 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的
进阶
你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。
代码解析
vector排序法
class Solution {
public:
//对vector排序的谓词,前面加static
static bool compare(pair<int, int> map1, pair<int, int> map2)
{
return map1.second > map2.second;
}
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> num_map; //map统计出现的次数
vector<pair<int ,int >> buf; //缓存vector,用作排序
vector<int> result;
for( auto i:nums)
{
num_map[i]++; //统计出现的次数
}
for ( auto it : num_map) //将map中的数据存到vector中,用pair的形式
{
buf.push_back(make_pair(it.first, it.second));
// cout<<it.first<<' '<<it.second<<endl;
}
sort(buf.begin(), buf.end(),compare); //排序,按照value的大小排序
for(int i = 0 ; i<k ;i++)
{
result.push_back(buf[i].first); //前k个值为结果
}
return result;
}
};
小顶堆
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> num_map;
vector<int> result;
// 对频率排序
// 定义一个小顶堆,大小为k
priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;
for( auto i:nums)
{
num_map[i]++;
}
for ( auto it : num_map)
{
pri_que.push(it);
if (pri_que.size() > k)// 如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
{
pri_que.pop();
}
}
for(int i = k - 1; i >= 0; i--) //小顶堆,先出的小,倒着装入数组
{
result.push_back( pri_que.top().first);
pri_que.pop();
}
return result;
}
};
map排序
class Solution {
public:
static bool cmp(const pair<int,int>&a, const pair<int,int>&b )
{
return a.second > b.second;
}
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> my_map;
vector<int> resulte;
for(int i=0 ; i<nums.size() ;i++)
{
my_map[nums[i]]++;
}
vector<pair<int,int>> tmp(my_map.begin(),my_map.end());
sort(tmp.begin(),tmp.end(),cmp);
for(int i=0 ; i<k ;i++)
{
resulte.push_back(tmp[i].first);
}
return resulte;
}
};