Day20-代码随想录-逆波兰表达式求值150+滑动窗口最大值239

逆波兰表达式求值150题目如下所示:

这道题不难,能一下子想到使用栈去操作,自己主要的纠结点在怎么把字符串的运算符提取为真的运算符,我这死脑筋,题目已经明确说明了有效的算符为+-*/,我还在思考要是用判断语句无法判断完所有的运算符(比如什么逻辑运算符等),所以其实直接用if-else来匹配即可,注意这里的"+"是字符串,不能用==来判断,得用"+".equals(s)来判断。

代码如下:

class Solution {
    public int evalRPN(String[] tokens) {
       Deque<Integer> stack = new LinkedList<>();
       //用栈的方式来解决,将数字先压入,一遇到运算符,将相邻的两个栈顶取出,
       //计算出结果后又将值压入栈,以此反复
       for(String s : tokens){
            if("+".equals(s)){
                stack.push(stack.pop() + stack.pop());
            }else if("-".equals(s)){
                stack.push(-stack.pop() + stack.pop());//-和/需要进行特殊处理
            }else if("*".equals(s)){
                stack.push(stack.pop() * stack.pop());
            }else if("/".equals(s)){
                int temp1 = stack.pop();
                int temp2 = stack.pop();
                stack.push(temp2/temp1);
            }else{
                stack.push(Integer.valueOf(s));
            }
       }
       return stack.pop();
    }
}

滑动窗口最大值题目如下所示:

暴力求解不是我们做这道题的最优,这里引入单调队列进行求解:

根据栈与队列的知识,我们很容易能想到将滑动窗口的元素全部入队,每向右移动,队头元素就被pop,新push元素进队尾,然后在这个队列中找到最大值返回,这是最理想的解法,但实际情况并没有这种数据结构。在这个队列里的元素肯定是要进行排序的,最大值放在出口,但问题是移动时怎么弹出元素!!所以引申到我们没必要维护窗口里的所有元素,只要维护有可能成为窗口里最大值的元素就可以了,同时保证队列里的元素数值是由大到小的。那么这个维护元素单调递减的队列就叫做单调队列,即单调递减或单调递增的队列。

单调队列不是一成不变的,而是不同场景不同写法,总之要保证队列里单调递减或递增的原则,所以叫做单调队列。 不要以为本题中的单调队列实现就是固定的写法哈。

注意:deque是stack和queue默认的底层实现容器,deque是可以两边扩展的,而且deque里元素并不是严格的连续分布的。

自定义一个单调队列代码如下:

//自定义一个单调队列
class MyQueue{
    Deque<Integer> deque = new LinkedList<>();
    //重新定义入队和出队操作
    //1.弹出元素时,比较当前要弹出的数值是否等于队列出口的数值,如果相等则弹出
    void poll(int val){
        if(!deque.isEmpty() && val == deque.peek()){
            deque.poll();
        }
    }
    //2.添加元素时,如果要添加的元素大于入口元素,则将入口元素弹出
    //这样才能保证队列单调递减
    void add(int val){
        while(!deque.isEmpty() && val > deque.getLast()){
            deque.removeLast();
        }
        deque.add(val);
    }
    //3.队列的队顶元素始终为最大值
    int peek(){
        return deque.peek();
    }
}

最终实现的代码如下:

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length == 1){
            return nums;
        }
        int len = nums.length - k +1;//存放最大值的数组的长度
        int[] res = new int[len];
        int num = 0;
        MyQueue myQueue = new MyQueue();
        //1.首先将前k个元素放入队列
        for(int i = 0; i < k; i++){
            myQueue.add(nums[i]);
        }
        res[num++] = myQueue.peek();
        //2.开始滑动窗口
        for(int i = k; i < nums.length; i++){
            //2.1 滑动窗口移除最前面的元素
            myQueue.poll(nums[i-k]);
            //2.2 滑动窗口加入最后面的元素
            myQueue.add(nums[i]);
            //2.3 记录最大值
            res[num++] = myQueue.peek();
        }
        return res;
    }
}

### 代码随想录算法训练营 Day20 学习内容与作业 #### 动态规划专题深入探讨 动态规划是一种通过把原问题分解为相对简单的子问题的方式来求解复杂问题的方法[^1]。 #### 主要学习内容 - **背包问题系列** - 背包问题是典型的动态规划应用场景之一。这类题目通常涉及给定容量的背包以及一系列具有不同价值和重量的物品,目标是在不超过总容量的情况下最大化所选物品的价值。 - **状态转移方程构建技巧** - 构建合适的状态转移方程对于解决动态规划问题是至关重要的。这涉及到定义好dp数组(或表格),并找到从前一个状态到下一个状态之间的关系表达式[^2]。 - **优化空间复杂度方法** - 对于某些特定类型的DP问题,可以采用滚动数组等方式来减少所需的空间开销,从而提高程序效率[^3]。 #### 实战练习题解析 ##### 题目:零钱兑换 (Coin Change) 描述:给定不同面额的硬币 coins 和一个总金额 amount。编写函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 `-1`。 解决方案: ```python def coinChange(coins, amount): dp = [float('inf')] * (amount + 1) dp[0] = 0 for i in range(1, amount + 1): for coin in coins: if i >= coin and dp[i - coin] != float('inf'): dp[i] = min(dp[i], dp[i - coin] + 1) return dp[-1] if dp[-1] != float('inf') else -1 ``` 此段代码实现了基于自底向上的迭代方式解决问题,其中 `dp[i]` 表示达到金额 `i` 所需最小数量的硬币数目[^4]。 ##### 题目:完全平方数 (Perfect Squares) 描述:给出正整数 n ,找出若干个不同的 完全平方数 (比如 1, 4, 9 ...)使得它们的和等于n 。问至少需要几个这样的完全平方数? 解答思路同上一题类似,只是这里的“硬币”变成了各个可能的完全平方数值。 ```python import math def numSquares(n): square_nums = set([i*i for i in range(int(math.sqrt(n))+1)]) dp = [float('inf')] *(n+1) dp[0] = 0 for i in range(1,n+1): for sq in square_nums: if i>=sq: dp[i]=min(dp[i],dp[i-sq]+1); return dp[n]; ``` 这段代码同样运用了动态规划的思想去寻找最优解路径,并利用集合存储所有小于等于输入值的最大平方根内的平方数作为候选集[^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值