34、逆波兰数
题目简介:
给你一个字符串数组 tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
注意:
- 有效的算符为
'+'
、'-'
、'*'
和'/'
。 - 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
- 两个整数之间的除法总是 向零截断 。
- 表达式中不含除零运算。
- 输入是一个根据逆波兰表示法表示的算术表达式。
- 答案及所有中间计算结果可以用 32 位 整数表示。
初见思路:
没有这东西
算法思路:
利用栈可以正确的处理后序排列的表达式,我学到了。第二、我还学到了stoll
,可以很方便的把string
变成int
数
class Solution {
public:
int evalRPN(vector<string>& tokens) {
int n = tokens.size();
stack<int> stack1;
for (int i = 0; i < n; i++) {
if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" ||
tokens[i] == "/") {
int temp1 = stack1.top();
stack1.pop();
int temp2 = stack1.top();
stack1.pop();
if (tokens[i] == "+") {
stack1.push(temp1 + temp2);
} else if (tokens[i] == "-") {
stack1.push(temp2 - temp1);
} else if (tokens[i] == "*") {
stack1.push(temp1 * temp2);
} else if (tokens[i] == "/") {
stack1.push(temp2 / temp1);
}
} else {
stack1.push(stoll(tokens[i]));
}
}
return stack1.top();
}
};
35、滑动窗口最大值
题目简介:
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
初见思路:
我想的就是两层循环把,外层遍历有多少个窗口,内层就遍历滑动窗空中的最大值。然后就水灵灵的超时了。用队列来优化嘛?怎么优化,我知道滑动窗口就是一个队列,一个进来就出去一个。这样可以节省时间吗?哪部分的时间呢?
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
vector<int> res;
for (int i = 0; i <= n - k; i++) {
int max = INT32_MIN;
for (int j = 0; j < k; j++) {
if (nums[i + j] > max) {
max = nums[i + j];
}
}
res.push_back(max);
}
return res;
}
};
算法思路:
我觉得算法思路里节省的还是内循环的比较过程,因为他一直维护了仍存活的最大值,而我们上面的最大值其实只存活了一次循环,结束之后我们又要再维护一个最大值,当k
足够大的时候,很自然就会拉长时间了。而算法的思路就是一直保持存活的最大值。
class Solution {
public:
deque<int> que;
void pop(int val){
if(!que.empty() && que.front() == val){
que.pop_front();
}
}
void push(int val){
while(!que.empty() && val > que.back()){
que.pop_back();
}
que.push_back(val);
}
int get_max(){
return que.front();
}
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
vector<int> res;
for(int i=0;i<k;i++){
push(nums[i]);
}
res.push_back(get_max());
for(int i =0 ; i<n-k; i++ ){
pop(nums[i]);
push(nums[i+k]);
res.push_back(get_max());
}
return res;
}
};
36、K个高频元素
题目简介:
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
初见思路:
遍历一遍数组,我就知道各个元素都出现了多少次了,最麻烦的是如何维护一个从大到小的根据出现次数的队列呢。优选队列可以自动维护一个单调队列我知道,但是我怎么根据出现的次数对应到哪个元素呢?定义一个map
再存一下各个元素的出现次数吗?但是key
是元素,次数是value
呀,我怎么根据value
找key
呢?
算法思路:
class Solution {
public:
class mycomparisom{
public:
bool operator()(const pair<int,int>& p1,const pair<int,int> &p2) const{
return p1.second > p2.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k) {
int n = nums.size();
unordered_map<int,int> map1;
for(auto a : nums){
map1[a]++;
}
priority_queue<pair<int,int>,vector<pair<int,int>>,mycomparisom> minHeap;
for(auto b = map1.begin();b !=map1.end();b++){
minHeap.push(*b);
if(minHeap.size() > k) minHeap.pop();
}
vector<int> res;
for(int i =0;i<k;i++){
int temp = minHeap.top().first;
res.push_back(temp);
minHeap.pop();
}
return res;
}
};
问题还是出在我对优先队列的不熟悉呀:
1、确实是用map
存入了次数和元素,这样才能找到对应关系。
2、如何利用优先队列呢,首先优先队列是可以自己定义比较方式的,也就是上方使用的仿函数方法,通过这个我们就可以定义如何存放优先队列中的值
3、定义优先队列的方式,你要给出元素的类型,给出存放的形式,也就是vector<pair<int,int>>
,然后给出自己比较的规则
4、大顶堆和小顶堆的实现方式,return
的时候,如果判断为真,就把操作数2
放到前面,操作数1
放到后面。
5、如果你想保留最大的k个值,你就要用小顶堆,这样再pop
的时候,才会把堆顶的数给pop
出去,反之亦然。