算法第十天|逆波兰表达式求值LeetCode150、滑动窗口最大值LeetCode239、前k个高频元素LeetCode347

今日总结:

        1、需要记住字符串转换成数字的函数 stoi与stoll

        2、在滑动窗口最大值中,需要着重体会如何获取窗口中的最大值的减枝行为

        3、在前k个高频元素中

                (1)知道堆是通过优先队列priority_queue创建的(默认大根堆)

priority_queue> que;

                (2)需要使用重载运算符,需要知道重载运算符的写法

//定义结构体
struct greater2{
    //定义比较函数
    bool operator()(const 类型&变量a,congst 类型&变量b)
    {
        return 变量a>变量b;
    }
}
priority_queue,vector>,greater2> que;

逆波兰表达式求值

题目链接:LeetCode150、逆波兰表达式求值

整体思路:

        因为在字符串中,只有遇到符号才会让符号前边的两个数使用符号做运算:

                所以可以使用栈的先进后出特性,当遇到符号,弹出栈顶两个元素,运算完成输入到栈顶。

        难点:

        给的是字符串,但是需要使用的是具体的整数进行运算,所以需要将string类型的字符转换成整数,使用:

        stoi-->将字符串转换成整型,如果存在不是数字的位置(或者超出int),会抛出异常

        stoll-->转换成longlong类型

class Solution {
public:
    int evalRPN(vector& tokens) {
        //整体使用一个栈记录数字,当出现运算符,弹出栈顶两个值进行运算,运算完成将值填入栈顶
        //注意是字符串,需要转换成数字
        stack  stk;
        //注意是32位整数
        long long num1=0,num2=0,res=0;
        for(auto i : tokens)
        {
            if(i=="+"||i=="-"||i=="*"||i=="/")
            {
                num2=stk.top();
                stk.pop();
                num1 = stk.top();
                stk.pop();
                if(i=="+")res = num1+num2;
                if(i=="-")res = num1-num2;
                if(i=="*")res = num1*num2;
                if(i=="/")res = num1/num2; 
                stk.push(res);
            }
            else stk.push(stoi(i));//存入的是数字
        }
        return stk.top();
        
    }
};

滑动窗口最大值

题目链接:LeetCode239、滑动窗口最大值

整体思路:

        滑动窗口-->使用一个双端队列来记录窗口元素的下标

        1、遍历字符串时,有新的元素要加入到窗口时:

               (1)判断当前窗口的大小,如果加入后窗口已经超过了k,需要让窗口左端向右移动

                (2)判断当前元素与窗口中最右端的元素大小,如果当前元素大于窗口最右端的元素,说明在窗口移动过程中还存在当前最右端的元素时,窗口中最大的元素一定不可能是窗口最右端的元素-->可以从窗口中从右向左判断是不是比当前元素大(需要保证双端队列不为空)-->最终窗口中会从左向右递减的状态

                (3)将当前的元素下标添加到双端队列

        2、遍历字符串时,如果刚开始窗口大小还没有到达k,不能输出窗口的最大元素

class Solution {
public:
    vector maxSlidingWindow(vector& nums, int k) {
        //滑动窗口的问题:使用一个数组作为双端队列,记录窗口内元素的下标
        //1、当新元素进入到窗口,如果当前的值在滑动窗口中最大-->在滑动窗口的尾端移出当前元素之前,当前元素前边的所有元素都不可能是最大值,可以直接去除进行减枝
        //2、需要确定滑动窗口已经满足窗口大小,在没有到达窗口大小的时候,不能输出值
        //3、需要确定:当遍历数组的时候,滑动窗口的大小是不是已经超过要求的k了,如果超过需要将窗口的尾端向下一位移动

        //定义一个数组模拟的双端队列deque,保存窗口中满足要求的下标:
        int deq[100010]={0};
        int tt=-1;//队尾添加元素,从-1开始
        int hh=0;//队头,从0开始,记录窗口的最后位置
        vectorres;//记录结果
        for(int i=0;i=hh&&i-deq[hh]+1>k)hh++;

            //记录当前元素的下标到双端队列中

            //判断当前元素与窗口中的元素右端的元素大小,如果是大的就把之前小的从窗口中删除
            while(tt>=hh&&nums[i]>=nums[deq[tt]])
            {
                tt--;
            }
            //将当前值填入记录窗口下标的双端队列
            deq[++tt] = i;
            //此时双端队列记录的窗口中,从左到右是从大到小的顺序,只要输出deq[hh]所代表的元素,就是窗口的最大值
            //需要判断此时的窗口是不是满足了=k
            if(i-k+1>=0)
            {
                res.push_back(nums[deq[hh]]);
            }
        }
        return res;
        
    }
};

前k个高频元素LeetCode347

题目链接:LeetCode347、前k个高频元素

整体思路:

        可以分成三部分求解:

        1、计算数组元素的频率:通过哈希表(哈希表是“空间换时间 ”,通过哈希函数将数据压缩存储,实现O(1)的查找效率。在解决存在性检测、状态记录等问题有很好的效果

        2、对频率进行排序(堆排序、sort、快排)但是注意是[元素,频率]的键值对

        3、对前k个频率进行输出

思路1:使用无序映射unordered_map与小根堆(代码随想录)

        难点:

                (1)小根堆实现通过优先队列priority_queue,但是要维护一个k大小的堆,当大于k的时候,将频率小的弹出,判断的是map中的value-->重载运算符,使其对second进行判断

class Solution {
public:
    vector topKFrequent(vector& nums, int k) {
        //思路:
        //  1、需要求数组中出现数的频率
        //  2、比较频率大小,
        //  3、返回频率前k个元素

        //对于统计出现的频率,可以使用哈希表进行统计,使用unordered_map进行统计
        //对于计算频率大小,可以使用堆来获取前k个元素

        unordered_map  map;
        for(auto i  :  nums)
        {
            map[i]++;
        }

        //使用优先队列模拟堆,但是默认是大根堆,需要重载运算符变成小根堆
        //注意:小根堆需要判断的是map中的value,而不是key,所以不能直接使用给定的重载,而是需要自己手写一个针对second的重载运算符小根堆
        struct greater2{
            bool operator()(const pair&a,const pair&b)
            {
                return a.second>b.second;
            }
        };

        //优先队列定义小根堆
        priority_queue ,vector>,greater2> que;
        //使用固定大小的小根堆遍历整个数值
        for(auto it =map.begin();it!=map.end();it++)
        {
            que.push(*it);
            if(que.size()>k)que.pop();
        }
        //弹出前k个元素
        int i=k;
        //记录前k个元素 
        vectorres;
        while(i--)
        {
            res.push_back(que.top().first);
            que.pop();
        }
        return res;
    }
};

思路2:使用无序映射unordered_map与sort(未实现,今天有点累了)

        难点:

                (1)sort对map中的value进行排序(需要先将map转换成vector>)

思路3:使用快速排序法

        难点:

                (1)需要先将map转换成vector>

                (2)需要使用快排对pair的second进行排序

你可能感兴趣的:(数据结构)