代码随想录Day12
LeetCode 150 逆波兰表达式求值
根据 逆波兰表示法,求表达式的值。
有效的运算符包括 + , - , * , / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
- 输入: ["2", "1", "+", "3", " * "]
- 输出: 9
- 解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
- 输入: ["4", "13", "5", "/", "+"]
- 输出: 6
- 解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:
-
输入: ["10", "6", "9", "3", "+", "-11", " * ", "/", " * ", "17", "+", "5", "+"]
-
输出: 22
思路:
逆波兰表达式是一种后缀表达式。我们平时使用的表达式是一种中缀表达式,需要去关注括号。
如果逆波兰表达式,不需要关注括号,直接计算即可。
遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。
栈擅长做两个数的计算操作。遇到两数计算的问题多想想用栈来解决。
代码:
class Solution { public int evalRPN(String[] tokens) { Deque<Integer> stack = new LinkedList(); for (String s : tokens) { if ("+".equals(s)) { // leetcode 内置jdk的问题,不能使用==判断字符串是否相等 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(); } }
LeetCode239 滑动窗口最大值
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
进阶:
你能在线性时间复杂度内解决此题吗?
思路:
单调队列。每次pop一个push一个。然后求一下窗口里的最大值即可。
关键的地方在于如何求最大值
1加入,3加入(比较和1谁大,3大,把1舍弃),-1加入(3比-1大,保留)
我们在头处维护最大值即可。
- pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
- push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止
保持如上规则,每次窗口移动的时候,只要问que.front()就可以返回当前窗口的最大值。
代码:
//解法一 //自定义数组 class MyQueue { Deque<Integer> deque = new LinkedList<>(); //弹出元素时,比较当前要弹出的数值是否等于队列出口的数值,如果相等则弹出 //同时判断队列当前是否为空 void poll(int val) { if (!deque.isEmpty() && val == deque.peek()) { deque.poll(); } } //添加元素时,如果要添加的元素大于入口处的元素,就将入口元素弹出 //保证队列元素单调递减 //比如此时队列元素3,1,2将要入队,比1大,所以1弹出,此时队列:3,2 void add(int val) { while (!deque.isEmpty() && val > deque.getLast()) { deque.removeLast(); } deque.add(val); } //队列队顶元素始终为最大值 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(); //先将前k的元素放入队列 for (int i = 0; i < k; i++) { myQueue.add(nums[i]); } res[num++] = myQueue.peek(); for (int i = k; i < nums.length; i++) { //滑动窗口移除最前面的元素,移除是判断该元素是否放入队列 myQueue.poll(nums[i - k]); //滑动窗口加入最后面的元素 myQueue.add(nums[i]); //记录对应的最大值 res[num++] = myQueue.peek(); } return res; } } //解法二 //利用双端队列手动实现单调队列 /** * 用一个单调队列来存储对应的下标,每当窗口滑动的时候,直接取队列的头部指针对应的值放入结果集即可 * 单调队列类似 (tail -->) 3 --> 2 --> 1 --> 0 (--> head) (右边为头结点,元素存的是下标) */ class Solution { public int[] maxSlidingWindow(int[] nums, int k) { ArrayDeque<Integer> deque = new ArrayDeque<>(); int n = nums.length; int[] res = new int[n - k + 1]; int idx = 0; for(int i = 0; i < n; i++) { // 根据题意,i为nums下标,是要在[i - k + 1, i] 中选到最大值,只需要保证两点 // 1.队列头结点需要在[i - k + 1, i]范围内,不符合则要弹出 while(!deque.isEmpty() && deque.peek() < i - k + 1){ deque.poll(); } // 2.既然是单调,就要保证每次放进去的数字要比末尾的都大,否则也弹出 while(!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) { deque.pollLast(); } deque.offer(i); // 因为单调,当i增长到符合第一个k范围的时候,每滑动一步都将队列头节点放入结果就行了 if(i >= k - 1){ res[idx++] = nums[deque.peek()]; } } return res; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!