代码随想录day11||150,逆波兰表达式求值 239,滑动窗口最大值 347,前k个高频元素

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;

这段代码的详细解释是:

  1. priority_queue:这是C++标准库中的优先队列(priority_queue)容器类。优先队列是一个按特定顺序管理元素的队列,通常用于维护一个最大值或最小值的集合。

  2. <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是一个自定义的比较器类,用于指定元素从小到大排序。

  3. 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算法里看

  • 34
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值