150,逆波兰表达式求值
题目描述:
给你一个字符串数组 tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
注意:
- 有效的算符为
'+'
、'-'
、'*'
和'/'
。 - 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
- 两个整数之间的除法总是 向零截断 。
- 表达式中不含除零运算。
- 输入是一个根据逆波兰表示法表示的算术表达式。
- 答案及所有中间计算结果可以用 32 位 整数表示。
示例 1:
输入:tokens = ["2","1","+","3","*"] 输出:9 解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入:tokens = ["4","13","5","/","+"] 输出:6 解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
有图像理解:
/*当遇到的是符号时,就以此符号来进行前两个数的运算,不是符号,就放入栈中,用运算完的结果替换掉使用该符号的数(及时弹出运算过的数字)*/
代码:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<long long>st;
for(int i=0;i<tokens.size();i++) {
if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/")
{
//记住这个值就赶紧弹出
long long num1=st.top();
st.pop();
long long num2=st.top();
st.pop();
//这里注意,是第二个数 符号 第一个数 顺序不能反
if(tokens[i]== "+" )st.push(num2 + num1);
if(tokens[i]== "-" )st.push(num2 - num1);
if(tokens[i]== "*")st.push(num2* num1);
if(tokens[i]== "/" )st.push(num2 / num1);
} else {
st.push(stoll(tokens[i]));
}
}
int result= st.top();
st.pop();
return result;
}
};
239,滑动窗口最大值
题目描述:
给你一个整数数组 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]
我自己的代码:(超出时间限制,复杂度有点高,循环里套循环)
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> result;
for(int i=0;i<=nums.size()-k;i++)
{
int temp=numeric_limits<int>::min();
for(int j=i;j<i+k;j++)
{
temp=max(nums[j],temp);
}
result.push_back(temp);
}
return result;
}
};
第二种方法!
用队列实现,要用自定义的队列类型,实现单调队列
单调队列:单调递减或者单调递增的队列,因为这样,我们每往下访问一个窗口,如果是单调递减的队列,那么,最大值一定是front()。
所以我们要自己实现这个单调队列
代码:
class Solution {
private:
class MyQueue { //单调队列(从大到小)
public:
deque<int> que; // 使用deque来实现单调队列
void pop(int value) {
if (!que.empty() && value == que.front()) {
que.pop_front();
}
}
// 保持队列里的数值是单调从大到小
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的元素的最大值
//每一次i+1,都是去下一个窗口
for (int i = k; i < nums.size(); i++) {
que.pop(nums[i - k]); // 滑动窗口移除最前面元素
que.push(nums[i]); // 滑动窗口前加入最后面的元素
result.push_back(que.front()); // 记录对应的最大值
}
return result;
}
};
图像:
347,前k个高频元素
题目描述:
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2]
示例 2:
输入: nums = [1], k = 1 输出: [1]
这题用小顶堆实现,小顶堆会自动排序,但我们此时的小顶堆的排序需要自己定义,让这个顶堆的排序是根据数字出现的次数来排序
代码是:
// 小顶堆
class mycomparison {
public:
bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
//.second 就是用来规定排序的根据是出现的次数,类似sort的自己规定
return lhs.second > rhs.second;
}
};
完整代码:
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;
}
};
这段代码里有一段比较生疏的语法:
priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;
这段代码的详细解释是:
-
priority_queue
:这是C++标准库中的优先队列(priority_queue)容器类。优先队列是一个按特定顺序管理元素的队列,通常用于维护一个最大值或最小值的集合。 -
<pair<int, int>, vector<pair<int, int>>, mycomparison>
:这是priority_queue
的模板参数,用于指定该优先队列的元素类型、底层容器类型和比较器类型。-
pair<int, int>
:这是优先队列中存储的元素类型。在这里,优先队列存储的是pair<int, int>
类型的元素,其中每个pair包含两个int值。 -
vector<pair<int, int>>
:这是优先队列的底层容器类型。在此情况下,优先队列使用vector<pair<int, int>>
作为其底层容器来存储元素。 -
mycomparison
:这是自定义的比较器类型,用于指定优先队列中元素的排序方式。在这里,mycomparison
是一个自定义的比较器类,用于指定元素从小到大排序。
-
-
pri_que
:这是定义的优先队列对象的名称。在这个语句中,我们定义了一个名为pri_que
的优先队列对象,它将包含pair<int, int>
类型的元素,使用vector<pair<int, int>>
作为底层容器,并使用mycomparison
作为比较器。
priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;
这句话的语法是在定义一个名为pri_que
的优先队列对象,该对象存储pair<int, int>
类型的元素,使用vector<pair<int, int>>
作为底层容器,并使用自定义的mycomparison
比较器类来管理元素的排序。
堆这个东西可以去Hello算法里看