day11 力扣150. 逆波兰表达式求值 力扣239. 滑动窗口最大值 力扣347.前 K 个高频元素

 逆波兰表达式求值

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

示例 1:

输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2:

输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

示例 3:

输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

提示:

  • 1 <= tokens.length <= 104
  • tokens[i] 是一个算符("+""-""*" 或 "/"),或是在范围 [-200, 200] 内的一个整数

逆波兰表达式:

逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。

  • 平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
  • 该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。

逆波兰表达式主要有以下两个优点:

  • 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
  • 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

我们可以在一个for中,遇见数字就转换类型,放入栈中,如果遇见符号,就将前俩个top值取出来,并且在栈里删除,进行相应的符号处理,再放入栈中。

注意:转换类型的书写方式 如果是string变成int 就是 stoi(token[i]),如果是string变成long long  就是stoll (token[i])。

           取数时要考虑到先取出来的是加数/减数/乘数/除数,而后取出来的才是被加数/被减数/被乘数/被除数。

class Solution {
public:
    int evalRPN(vector& tokens) {
        stack st;
        int len = tokens.size();
        for(int i = 0 ;i < len;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(num1+num2);
                if(tokens[i]=="-")st.push(num2-num1);
                if(tokens[i]=="*")st.push(num1*num2);
                if(tokens[i]=="/")st.push(num2/num1);
            }
            else 
            {
                st.push(stoll(tokens[i]));
            }
        }
        return st.top();
    }
};

滑动窗口最大值

给你一个整数数组 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]

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

做的第一道力扣困难题(确实难······)

我们需要自己构建一个以deque为基础的数据结构(命名为Myqueue),实现三个功能

1.pop(int value):如果deque的front等于这个value值,即deque最大的数是要离开滑动窗口的数,那么我们就deque.pop_front()

2.push(int value):我们的这个数据结构要保证是递减,那么在我们加入一个数的时候,我们要删除他前面小于他的数,则当value>deque.bcak(),那我们就删去他的尾数。注意这里的判断要用while循环。

3.max() :显示最大值,即输出他的front值。

后面主函数就很好写了。我觉得这个题蛮好的,当我们已知的数据结构无法适配一道题时,我们可以改造一些已知数据结构去做这道题。

class Solution {
public:
    class Myqueue
    {
        public:
        deque 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 max()
        {
            return que.front();
        }
    };
    vector maxSlidingWindow(vector& nums, int k) {
        Myqueue mqe;
        vector result;
        for(int i = 0;i

前 K 个高频元素

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

输入: nums = [1], k = 1
输出: [1]

提示:

  • 1 <= nums.length <= 105
  • k 的取值范围是 [1, 数组中不相同的元素的个数]
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。

头一次接触堆这个名词,看了好几遍思路和视频,才看懂是什么意思, 但还是不知道怎么去写,抄着写了一遍题解,先解释一下思路,二刷的时候争取自己做出来!

这道题目主要涉及到如下三块内容:

  1. 要统计元素出现频率
  2. 对频率排序
  3. 找出前K个高频元素

第一个问题很好解决,拿一个map去统计一下即可。

第二个问题,我们采用小顶堆来处理,即优先级队列。

优先级队列分为俩种,一种是小顶堆,一种是大顶堆。它们都不是以先后放入顺序排列的,而是以大小顺序排列,小顶堆的top就是最小的数,大顶堆的top自然就是最大的数。

第三个问题,要找出前k个,那我们设一个k个大小的小顶堆即可每次将map传进去,如果小顶堆的数量大于k,那我们就pop小顶堆,这样小顶堆的top(即map.second)也就是小顶堆里的最小频率的pair就会被删除。

这里的如何去写我就不过多介绍了(主要是说不明白 ^_^)题解如下:

class Solution {
public:
    class Mycomparsion
    {
        public:
        bool operator()(const pair& lhs,const pair& rhs)
        {
            return lhs.second > rhs.second;
        }
    };
    vector topKFrequent(vector& nums, int k) {
        unordered_map map;
        for(int num:nums)
        {
            map[num]++;
        }
        priority_queue,vector>,Mycomparsion> pri_que;
        for(unordered_map::iterator it = map.begin();it!=map.end();it++)
        {
            pri_que.push(*it);
            if(pri_que.size()>k)
            {
                pri_que.pop();
            }
        }
        vector result(k);
        for (int i = k - 1; i >= 0; i--) {
            result[i] = pri_que.top().first;
            pri_que.pop();
        }
        return result;
    }
};

你可能感兴趣的:(day11 力扣150. 逆波兰表达式求值 力扣239. 滑动窗口最大值 力扣347.前 K 个高频元素)