代码随想录第12天 | 栈与队列part02 总结

题目:150. 逆波兰表达式求值

思路:

1.使用栈,存储数字,遇到运算符,则取出栈顶两个数进行运算,结果在存入栈中。

坑:

  1. 加减乘除运算符没有别的技巧,就是if相等 然后 +-*/ ,switch 也可以
  2. 栈使用long long型,int型会溢出
  3. 使用 "+"不是单引号'+',vector<string类型> 不是 vector<char类型>
  4. 编译错误,num1未定义, 作用域问题, if后没加{}
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<long long  >stack;
        for(auto & str:tokens){//注意引用&
            if(str=="+"||str=="-"||str=="*"||str=="/") {//string类型是双引号""
                long long num1=stack.top();
                stack.pop();
                long long num2=stack.top();
                stack.pop();
                long long  sum=0;
                if(str=="+")  sum=num2+num1;
                if(str=="-")  sum=num2-num1;
                if(str=="*")  sum=num2*num1;
                if(str=="/")  sum=num2/num1;      
                stack.push(sum);
            }else{
                stack.push(stoll(str));//stoll()是string转long long 类型函数
            }
        } 
        return stack.top();
    }
};

补充:

字符串类型转换
1.[数字] 转换 “字符串”
【函数名】
to_string(数字类型); //数字类型 int long float 等
2.“字符串” 转换 [数字]
【函数名】
stoi() 对应 int
stol() 对应 long
stoll() 对应 long long

题目:239. 滑动窗口最大值(二刷题)

思路:

  1. 暴力法,两层循环,一层遍历,一层遍历滑动窗口内,
    时间复杂度:O(n^2)
  2. 滑动窗口,左右删除,使用双端队列deque单调队列,将滑动窗口中的值存入队列,一直保持最大值在队首,新添加元素大于队首,则全部删除,反之添加在队首后
    单调对列保存的是下标
    时间复杂度:O(n)

坑:

笑鼠,看错三次题。下次好好理解题目

  1. 保持单调队列的递减性,以及使用下标判断,最大值是否在窗口内,
class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int > result ;
        deque<int> deque; //保存索引下标
        //不通过, 单调栈内未递减
        for(int i=0;i<nums.size();i++){
            //从队尾加入新元素,新元素比队尾大,删除队尾,保持单调递减,队首为滑动窗口内最大值
            while(!deque.empty()&&nums[deque.back()]<=nums[i]){
                deque.pop_back();
            }
            // 添加元素
            deque.push_back(i);
            //队列保存的是下标,窗口在移动,所以判断队首是否要移除窗口
            if(i-deque.front()>=k){  
                deque.pop_front();
            }   
            if(i>=k-1){
                result.push_back(nums[deque.front()]);
            }
        }
        return result;
    }
};

补充:

单调队列:保持单调递减或递增的原则的队列
双向队列deque

  1. 可以在队列的两端进行元素的插入和删除操作,deque是C++STL(标准模板库)中的一种容器,
  2. 包含#include
  3. 常用函数
push_back()//在队列的尾部插入元素。
emplace_front()//与push_front()的作用一样 
push_front()//在队列的头部插入元素。
emplace_back()//与push_back()的作用一样 
pop_back()//删除队列尾部的元素。
pop_front()//删除队列头部的元素。
back()//返回队列尾部元素的引用。
front()//返回队列头部元素的引用。
clear()//清空队列中的所有元素。
empty()//判断队列是否为空。
size()//返回队列中元素的个数。
begin()//返回头位置的迭代器
end()//返回尾+1位置的迭代器
rbegin()//返回逆头位置的迭代器 
rend()//返回逆尾-1位置的迭代器 
insert()//在指定位置插入元素 
erase()//在指定位置删除元素 

题目:347.前 K 个高频元素(二刷题)

思路:

  1. 使用map保存元素和出现频率,使用优先级队列进行排序(小顶堆),

坑:

  1. 优先级队列 container是容器类型,可以是vector,queue等用数组实现的容器,不能是list,默认可以用vector;
  2. 报错runtime error: reference binding to null pointer of type 'int' (stl_vector.h)
    忽略了vector容器注意事项而报的错
    原因:vector在还没有分配任何空间时还不能像数组一样用下标形式去访问vector的
class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        //1.计算元素出现的频率
        unordered_map<int,int > map;//key存元素,value存频率
        for(auto &c: nums){
            map[c]++;// 不用find查找,直接添加
        }
        //2. 使用优先级队列 小顶堆对频率排序,
        //先自定义排序函数
        struct cmp{
            bool operator()(pair<int,int>&p1,pair<int,int>&p2){   
                return p1.second>p2.second;//小顶堆是较大元素下沉
            }
        }; //报错,忘加;
        priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> pri_q;
        for(auto &a: map){
            pri_q.push(a);
            if(pri_q.size()>k)
                pri_q.pop();
        }
        // 3.排序过后,转成vector<int>类型 return
        //错误,因为是小顶堆,所以需要倒序存入vector
        vector<int> result;
        for(int i=k-1;i>=0;i--){
            result.push_back(pri_q.top().first);
            pri_q.pop();
        }
        return result;
    }
};

补充:

优先级队列
一般队列是先进先出,从队尾入队,从队首出队。
优先级队列(priority_queue):给元素赋予优先级,优先级高的先出队。像数据结构 堆。
优先级队列的底层是最大堆或最小堆。大顶堆(堆头是最大元素,较小的元素下沉,less<),小顶堆(堆头是最小元素,较大的元素下沉greater>)

  1. 优先级队列的定义如下:
首先要包含头文件#include<queue>
priority_queue<typename, container, functional>

·typename是数据的类型;
·container是容器类型,可以是vector,queue等用数组实现的容器,不能是list,默认可以用vector;
·functional是比较的方式,默认大顶堆(元素越大,优先级越高),(c++可以直接使用自带的less和greater函数,默认的大顶堆是less函数,元素小于当前节点下沉)
使用自定义的数据类型的时候,可以重写比较函数,也可以进行运算符重载(less重载小于“<”运算符,构造大顶堆;greater重载大于“>”运算符,构造小顶堆)。

//重写仿函数,完成less的功能,也可以用class定义类,此时需要将运算符重载函数设为public
//结构体struct中默认是访问类型是public
struct cmp    
{
	bool operator() ( Data &a, Data &b) {
		return a.getId() < b.getId();
	}
};
  1. 优先队列具有队列的所有特性,包括队列的基本操作,只是在这基础上添加了内部的一个排序,它本质是一个堆实现的。
    和队列基本操作相同:
top 访问队头元素
empty 队列是否为空
size 返回队列内元素个数
push 插入元素到队尾 ( **并排序** )
emplace 原地构造一个元素并插入队列
pop 弹出队头元素
swap 交换内容

栈与队列总结

  1. 栈与队列的特性和基本操作
  2. 底层实现
  3. 单调队列
  4. 优先级队列
    堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子的值。 如果父亲结点是大于等于左右孩子就是大顶堆,小于等于左右孩子就是小顶堆。

今日总结

需补充堆的相关知识

posted @ 2024-06-18 23:22  跳圈  阅读(22)  评论(0)    收藏  举报