Day14 LeetCode20.有效的括号 1047. 删除字符串中的所有相邻重复项 150. 逆波兰表达式求值 239. 滑动窗口最大值 347. 前 K 个高频元素

  题目:20. 有效的括号 - 力扣(LeetCode​​​​​​

思路:

        1.第一种情况左括号多了:字符串遍历结束,如果栈中元素不为空,证明左括号多了。

        2.第二种情况右括号多了:当栈为空,此时字符串遍历还未结束说明右括号多了。

        3.第三种情况左右括号不匹配:栈顶元素和字符串中元素未匹配,证明左右括号未匹配上。

        4. 第四种情况左右括号匹配:栈为空。

代码:
 

class Solution {
public:
    bool isValid(string s) {
        stack<char> st;
        if(s.size() % 2 != 0) return false;
        for(int i = 0; i < s.size(); i++){
            if(s[i] == '('){
                st.push(')');
            }else if(s[i] == '{'){
                st.push('}');
            }else if(s[i] == '['){
                st.push(']');
            //2.第二种情况右括号多了:当栈为空,此时字符串遍历还未结束说明右括号多了,返回false;
            //3.第三种情况左右括号不匹配:栈顶元素和字符串中元素未匹配,证明左右括号未匹配上,返回false.
            }else if(st.empty() || s[i] != st.top()){
                return false;
            }else{
                st.pop();//左右括号匹配上了,直接弹出栈里的元素
            }
        }
        return st.empty();//1.此时字符串遍历结束,如果栈中元素不为空,证明左括号多了,
        //属于第一种情况左括号多了,返回false;如果为空,证明左右括号都匹配上了,返回true.
    }
};

题目:1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode) 

思路:

        1.建立一个栈,用来存放我们遍历过的元素,当遍历当前的这个元素的时候,去栈里看一下我们是不是遍历过相同数值的相邻元素,然后再去做对应的消除操作。

        2.最后从栈里弹出的时候,由于弹出的字符串是逆序的,所以需要反转一下。

代码:

class Solution {
public:
    string removeDuplicates(string s) {
        stack<char> st;
        string res = "";
        
        for(int i = 0; i < s.size(); i++){
            if(st.empty() || s[i] != st.top()){//如果栈为空,直接往栈里添加元素;如果不为空,则判断栈顶元素和此时遍历的元素是否相等
                st.push(s[i]);
            }else{
                st.pop();
            }
        }
        while(!st.empty()){
            res += st.top();
            st.pop();
        }
        reverse(res.begin(), res.end());
        return res;
    }
};

 题目:150. 逆波兰表达式求值 - 力扣(LeetCode)

思路:

         1.逆波兰表达式相当于是二叉树中的后序遍历,其实总体思路和上一道题删除字符串中所有相邻重复项一样,建立一个栈,如果不是操作符就入栈;如果遇见操作符,如+,-,*,/,就把栈顶元素num1和栈顶元素后一个元素num2依次弹出,操作这两个num,比如遇见+,就计算num2 +  num1,并把计算得到的结果再次压入栈,最后栈中剩下的元素就是表达式求值的结果,直接返回。

代码:

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]));
            }   
            
        }
        return st.top();
    }
};

题目:239. 滑动窗口最大值 - 力扣(LeetCode) 

思路:

        使用deque设计一个由大到小的单调队列,队列没有必要维护窗口里的所有元素,只需要维护有可能成为窗口里最大值的元素就可以了,同时保证队列里的元素数值是由大到小的。

设计单调队列的时候,pop,和push操作要保持如下规则:

  1. pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
  2. push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止

保持如上规则,每次窗口移动的时候,只要问que.front()就可以返回当前窗口的最大值。

具体分析见:代码随想录 (programmercarl.com)

代码:

class Solution {
private:
    class MyQueue{//单调队列,由大到小
    public:
        deque<int> que;//使用deque来实现单调队列
         // 每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
        // 同时pop之前判断队列当前是否为空。
        void pop(int value){  
            if(!que.empty() && value == que.front()){
                que.pop_front();
            }
        }
        // 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
        // 这样就保持了队列里的数值是单调从大到小的了。
        void push(int value){
            while(!que.empty() && value > que.back()){//注意这里是while不是if,因为这是一个不断弹出的过程
                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> res;
        // 先将前k的元素放进队列
        for(int i = 0; i < k; i++){
            que.push(nums[i]);
        }
        res.push_back(que.front());//记录前k个元素中的最大值
        for(int i = k; i < nums.size(); i++){
            que.pop(nums[i - k]);// 滑动窗口移除最前面元素
            que.push(nums[i]);// 滑动窗口前加入最后面的元素
            res.push_back(que.front());// 记录对应的最大值
        }
        return res;
    }
};

 题目:347. 前 K 个高频元素 - 力扣(LeetCode)

思路:

       1.要统计元素出现频率:使用unordered_map统计数组元素出现的频率,key存放元素值,value存放元素出现的频率。

       2.对频率排序:使用小顶堆对频率进行排序,得到前k个高频元素,可以使用优先级队列priority_queue来排序,至于为什么用小顶堆,不用大顶堆,是因为大顶堆每次弹出的都是频率最高的那个元素,那么最后剩下的k个元素就是频率最低的k个元素,所以使用小顶堆。

       3.找出前K个高频元素:最后建立一个数组vector,倒序输出到数组中。

具体分析见:代码随想录 (programmercarl.com)

代码:

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;
        //数组nums元素频率统计,key = nums[i] value = nums[i]出现的频率
        for(int i = 0; i < nums.size(); i++){
            map[nums[i]]++;
        }
        // 对频率排序
        // 定义一个小顶堆,大小为k,小顶堆是一颗完全二叉树,父结点的值小于等于孩子结点的值
        //优先级队列底层实现是一个堆(heap)
        priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> que;
        for(unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++){
            que.push(*it);
            if(que.size() > k){// 如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
                que.pop();//每次弹出的是频率最小的
            }
        }
        //经过小顶堆排序后,得到了出现频率前k高的元素
        // 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
        vector<int> res(k, 0);
        for(int i = k - 1; i >= 0; i--){
            res[i] = que.top().first;
            que.pop();
        }
        return res;

    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值