一,代码随想录leetcode150逆波兰表达式求值
看答案后的解题思路:首先先建立一个栈s1,然后用一个for循环对tokens数组进行遍历。如果遍历到数字,就让其入栈,如果遍历到的是符号,首先先定义num1和num2来接收栈最顶端的两个元素,然后让这两个元素出栈,完成对应的加减乘除运算后再让其入栈即可。在遍历结束时容器内只剩余一个元素,这个元素即为逆波兰表达式最终结果。获取其栈顶元素并返回即可。
class Solution {
public:
bool isNumber(string s){
if(s.empty())return false;
if(s[0]=='-'||s[0]=='+'){
if(s.size()==1)return false;
else{
s=s.substr(1);
}
}
for(char c:s){
if(!isdigit(c))return false;
}
return true;
}
int evalRPN(vector<string>& tokens) {
stack<long long> s1;
for(int i=0;i<tokens.size();i++){
if(isNumber(tokens[i]))s1.push(stoll(tokens[i]));
else{
long long num1=0,num2=0;
num1=s1.top();s1.pop();
num2=s1.top();s1.pop();
if(tokens[i]=="+")s1.push(num1+num2);
if(tokens[i]=="-")s1.push(num2-num1);
if(tokens[i]=="*")s1.push(num1*num2);
if(tokens[i]=="/")s1.push(num2/num1);
}
}
return s1.top();
}
};
小结:
本题目需要注意的有以下几点:
1,对于一个字符串是否为数字的判断:首先判断该字符串是否为空,如果是空的直接返回false。然后判断第一位,如果是符号并且字符串长度为1则也返回false。如果长度不是1,用s=s.substr(1)函数来将字符串取下标为1及以后的部分。然后对新的字符串进行遍历,用isdigit函数判断是否是数字,如果有一项不是数字就直接返回false,全部遍历完成后返回true,说明这个字符串是数字。其实本题目也可以判断符号来巧妙地避开这个,会方便一些。
2,因为定义的栈是int类型,但是将一个判断结果为数字的字符串入栈前要先进行类型转换。转换用sto来进行。
-
std::stoi
- 功能:将字符串转换为
int
类型。 - 用法:
cpp
std::string str = "123"; int num = std::stoi(str); // num = 123
- 功能:将字符串转换为
-
std::stol
- 功能:将字符串转换为
long
类型。 - 用法:
cpp
std::string str = "123456"; long num = std::stol(str); // num = 123456
- 功能:将字符串转换为
-
std::stoll
- 功能:将字符串转换为
long long
类型。 - 用法:
cpp
std::string str = "1234567890123"; long long num = std::stoll(str); // num = 1234567890123
- 功能:将字符串转换为
-
std::stof
- 功能:将字符串转换为
float
类型。 - 用法:
cpp
std::string str = "123.45"; float num = std::stof(str); // num = 123.45f
- 功能:将字符串转换为
-
std::stod
- 功能:将字符串转换为
double
类型。 - 用法:
cpp
std::string str = "123.456"; double num = std::stod(str); // num = 123.456
- 功能:将字符串转换为
-
std::stold
- 功能:将字符串转换为
long double
类型。 - 用法:
cpp
std::string str = "123.4567890123456789"; long double num = std::stold(str); // num = 123.4567890123456789
- 功能:将字符串转换为
二,代码随想录leetcode239滑动窗口最大值
看答案之后的解题思路:这个题目的核心思路是定义一个自己的数据结构,如果窗口每滑动一次,就进行一次入,出,取最大值的操作即可。下面来解释三个函数的思路:首先先定义一个deque(双端队列)pop:如果函数不为空,并且函数在字符串遍历的过程中要删去的数值等于当前队列中的front就让front的元素出队,否则说明要删去的元素在push过程中已经删去了,无需进行额外操作。push:如果函数不为空并且当前队列队尾的元素小于要入队的元素,就让队尾元素出队,最后让该元素入队,这样做可以保证队头元素始终是最大的元素。getmax:直接取对头元素即可。
class Solution {
private:
class MyQue{
public:
deque<int> que;
void pop(int value){
if(que.empty()==false&&que.front()==value)
que.pop_front();
}
void push(int value){
while(que.empty()==false&&que.back()<value){
que.pop_back();
}
que.push_back(value);
}
int getmax(){
return que.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
MyQue que;
vector<int> result;
for(int i=0;i<k;i++){
que.push(nums[i]);
}
result.push_back(que.getmax());
for(int i=k;i<nums.size();i++){
que.push(nums[i]);
que.pop(nums[i-k]);
result.push_back(que.getmax());
}
return result;
}
};
小结:本题需要注意以下几点:
1,deque双端队列在c++中的相关函数:
-
构造函数:
deque<T>
:默认构造函数,创建一个空的deque
。deque(size_type count, const T& value)
:创建一个包含count
个元素,每个元素初始化为value
的deque
。
-
基本操作:
push_back(const T& value)
:在双端队列的末尾插入一个元素。push_front(const T& value)
:在双端队列的开头插入一个元素。pop_back()
:删除双端队列的末尾元素。pop_front()
:删除双端队列的开头元素。
-
访问元素:
at(size_type pos)
:返回指定位置的元素,检查边界并抛出异常。operator[](size_type pos)
:返回指定位置的元素,不检查边界。front()
:返回第一个元素的引用。back()
:返回最后一个元素的引用。
-
容量操作:
size()
:返回deque
中的元素数量。empty()
:检查deque
是否为空。resize(size_type count)
:调整deque
的大小,若新的大小大于当前大小,则追加默认值。clear()
:移除所有元素。
-
迭代器:
begin()
:返回指向第一个元素的迭代器。end()
:返回指向最后一个元素后一个位置的迭代器。cbegin()
、cend()
:返回常量迭代器以进行只读访问。
-
其他操作:
insert(iterator pos, const T& value)
:在指定位置插入元素。erase(iterator pos)
:删除指定位置的元素。swap(deque& other)
:交换两个deque
的内容。
2,c++中vector相关函数
-
构造函数:
vector<T>()
:默认构造函数,创建一个空的vector
。vector(size_type count, const T& value)
:创建一个包含count
个元素,所有元素初始化为value
的vector
。vector(const vector& other)
:拷贝构造函数,创建一个vector
的副本。vector(vector&& other) noexcept
:移动构造函数,移动另一个vector
的内容。
-
基本操作:
push_back(const T& value)
:在vector
的末尾插入一个元素。pop_back()
:删除vector
的最后一个元素。insert(iterator pos, const T& value)
:在指定位置插入元素。erase(iterator pos)
:删除指定位置的元素。clear()
:移除所有元素,vector
变为空。
-
访问元素:
at(size_type pos)
:返回指定位置的元素,检查边界并抛出异常。operator[](size_type pos)
:返回指定位置的元素,不检查边界。front()
:返回第一个元素的引用。back()
:返回最后一个元素的引用。
-
容量操作:
size()
:返回vector
中的元素数量。capacity()
:返回vector
当前分配的存储空间大小。empty()
:检查vector
是否为空。resize(size_type count)
:调整vector
的大小。reserve(size_type new_cap)
:预留空间以容纳至少new_cap
个元素,避免频繁的内存重新分配。
-
迭代器:
begin()
:返回指向第一个元素的迭代器。end()
:返回指向最后一个元素后一个位置的迭代器。cbegin()
、cend()
:返回常量迭代器以进行只读访问。
-
其他操作:
swap(vector& other)
:交换两个vector
的内容。assign(size_type count, const T& value)
:用指定的count
个value
赋值给vector
。
3,代码随想录leetcode347前k个高频元素
看答案之后的解题思路 :统计出现频率前k高的元素,创建一个最大个数不超过k的小顶堆即可。首先先创建一个map,键是数组nums中的元素,值是这些元素出现的次数。通过一个循环,让这些数组中的元素和这些元素出现的次数体现到了map中。然后对map遍历,把所有的pair全部放到小顶堆中,最后建立一个数组,把这些元素倒序放到数组里面即可。
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;
}
};
小结:这题好多代码不会写,后面要学习补上。
1.c++如何定义一个小顶堆:
先自己写一个比较函数:struct MyComparison { bool operator()(const int& lhs, const int& rhs) { return lhs > rhs; // 比较规则:较大的元素优先级较低 } };再自己写一个定义小顶堆的代码priority_queue<int, vector<int>, MyComparison> minHeap;
2:priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;代码解释
priority_queue
:优先队列是一种特殊的队列数据结构,它能让我们按优先级顺序处理元素。pair<int, int>
:优先队列中的每个元素是一个整数对(pair),即包含两个整数的组合。vector<pair<int, int>>
:这是存储元素的底层容器,使用了一个vector
来存放pair<int, int>
类型的元素。mycomparison
:这是一个自定义的比较器,用于定义元素的优先级顺序。
3, bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) { return lhs.second > rhs.second; }代码解释:
这段代码定义了一个重载的运算符()
,该运算符用于比较两个pair<int, int>
类型的对象lhs
和rhs
。具体来说,它比较这两个对象的第二个元素(second
),并返回一个布尔值:
- 如果
lhs
的第二个元素大于rhs
的第二个元素,则返回true
; - 否则返回
false
。
这通常用于排序或优先队列中,表示希望根据第二个元素的大小进行排序。
4,为什么不用大顶堆?因为大顶堆根是最大的元素,而且要控制数组元素不超过k,所以必然涉及到元素的移除,移除会移除根,也就是最大的数字,与题目要求不符合,因此用小顶堆。