当前位置: 首页 > news >正文

Day11 >> 150、逆波兰表达式求值 + 239、滑动窗口最大值 + 347、前K个高频元素

代码随想录-栈

150、逆波兰表达式求值

刚开始看到题目的时候有点懵,不太了解逆波兰表达式,其实就是后缀表达式,是计算机的思考运行模式。这道题很适合用栈来解决,思路:

  1. 定义一个 Int 型的栈
  2. 然后去遍历字符串:
    1. 遍历到数值时,就压入栈中
    2. 遍历到运算符时,就取栈顶的两个元素进行运算,并将结果压入栈中
  3. 字符串遍历完成后,取出栈中的元素返回即可
class Solution { public int evalRPN(String[] tokens) { Stack<Integer> st = new Stack(); for (int i = 0; i < tokens.length; i++) { if ("+".equals(tokens[i]) || "-".equals(tokens[i]) || "*".equals(tokens[i]) || "/".equals(tokens[i])) { int number1 = st.pop(); int number2 = st.pop(); if ("+".equals(tokens[i])) st.push(number1 + number2); if ("-".equals(tokens[i])) st.push(number2 - number1); if ("*".equals(tokens[i])) st.push(number2 * number1); if ("/".equals(tokens[i])) st.push(number2 / number1); } else { st.push(Integer.valueOf(tokens[i])); } } return st.pop(); } }

做这道题目时,出了两种错误

  1. 对 Java 中字符类型的判断函数使用错误,写成了 "+" == tokens[i] ,这是错误的,因为 == 比较的是内存地址,也就是引用是否相同,而本题是需要比较字符串的内容,需要使用equals()
  2. 在取栈顶元素时,误用了栈的操作函数,写成了 int number1 = st.top() ,这里是使用了视频中卡哥讲的c++取栈顶元素的API,但是在Java中,应该使用 .pop() 函数
int number1 = st.pop(); // 弹出并返回栈顶元素 // 或 int number1 = st.peek(); // 仅返回栈顶元素(不弹出)

另外,在探索学习的过程中,AI还指出了当前代码太low了,存在两个可以优化的点:

  1. for循环中的索引遍历,可以使用for-each代替
  2. if-else 结构可以使用 switch 进行优化,使代码可读性更强,更简洁

优化完虽然代码行数变多了,但是执行效率提高了很多

class Solution { public int evalRPN(String[] tokens) { Stack<Integer> st = new Stack(); for (String token : tokens) { switch (token) { case "+" : st.push(st.pop() + st.pop()); break; case "*" : st.push(st.pop() * st.pop()); break; case "-" : int number1 = st.pop(); int number2 = st.pop(); st.push(number2 - number1); break; case "/" : int div1 = st.pop(); int div2 = st.pop(); st.push(div2 / div1); break; default : st.push(Integer.parseInt(token)); } } return st.pop(); } }

239、滑动窗口最大值

这道题看起来感觉思路挺清晰的,无非就是每滑动一次找出窗口范围内的最大值,但实现起来真是复杂,看了视频讲解,独立写的时候还卡住好多次,思路:

  1. 定义一个Deque,用于存储数组的索引,以此来定位滑动窗口的最大值(这里为什么存储下标,不直接存储数组的值?是因为存储下标,便于根据下标判断滑动窗口的有效位置)
  2. 定义一个整型数组,长度为 n-k+1,用于存储在滑动窗口中找到的最大值(这里为什么长度是 n-k+1,因为窗口在数组上移动时,有效位置范围是[0, n-k],所以共 n-k+1 个位置)
  3. 定义一个指针,从0开始,往数组中增加元素
  4. 开始遍历数组
    1. 遍历数组时,将满足条件的数值对应的下标存放入Deque中
    2. 由于题目要求在窗口范围内查找最大值,所以当窗口往后滑动的过程中,需要移除超出窗口内有效位置的下标,即 Deque.peek() < i-k+1
    3. 此外,为便于在窗口滑动的过程中获取最大值,将队列维护成单调队列,保持队列头部元素为最大值,如果即将加入的元素小于当前队列中已有元素,那正常加入队列,如果即将加入的元素大于当前队列中已有元素,那么就从队列尾部弹出当前队列的元素,直到队列中的元素大于即将加入的元素(因为要找最大值,如果加入的元素比之前的大,那么之前的元素就没必要再比较了,肯定不会是当前滑动窗口的最大值)
    4. 当 i 遍历到满足一个有效滑动窗口的位置时,就可以找出当前窗口的最大值了;由于是单调队列,所以后面获取最大值时,只需将队列头部元素对应下标的数组元素放入结果数组中即可
  5. 遍历完整个数组后,返回整型数组即可
class Solution { public int[] maxSlidingWindow(int[] nums, int k) { ArrayDeque<Integer> deque = new ArrayDeque(); int n = nums.length; int[] result = new int[n - k + 1]; int index = 0; for (int i = 0; i < n; i++) { while (!deque.isEmpty() && deque.peek() < i - k + 1) { deque.poll(); } while (!deque.isEmpty() && nums[i] > nums[deque.peekLast()]) { deque.pollLast(); } deque.offer(i); if (i >= k - 1) { result[index++] = nums[deque.peek()]; } } return result; } }

347、前K个高频元素

拿到题目想到了用map结构来记录每个元素出现的频次,然后再根据map中,最大的前K个value对应的key,从而得出结果。但根据value排序取对应的key好像挺复杂的,不知道怎么实现,去看了讲解后,才意识到需要用优先级队列这个数据结构,思路:

  1. 定义一个HashMap,用于存放元素、及其出现的频次
  2. 遍历数组,将元素值记为key,出现的频次记为value,存入map中
  3. 定义一个优先级队列,这里以小顶堆的方式定义该队列
  4. 遍历map:
    1. 如果当前队列的长度还没有达到 k,则继续往队列中增加value
    2. 如果当前队列的长度已经达到 k,则比较将要加入的 value 与当前队列头部的value,也就是堆顶的value,如果即将要加入的元素更大,则把堆顶弹出,在后面加入新元素
  5. 遍历完map,构建完小顶堆后,将堆元素逐个弹出,并存放在数组中即可
class Solution { public int[] topKFrequent(int[] nums, int k) { Map<Integer, Integer> map = new HashMap<>(); for (int num : nums) { map.put(num, map.getOrDefault(num, 0) + 1); } PriorityQueue<int[]> pq = new PriorityQueue<>((pair1, pair2) -> pair1[1] - pair2[1]); for (Map.Entry<Integer, Integer> entry : map.entrySet()) { if (pq.size() < k) { pq.add(new int[]{entry.getKey(), entry.getValue()}); } else { if (entry.getValue() > pq.peek()[1]) { pq.poll(); pq.add(new int[]{entry.getKey(), entry.getValue()}); } } } int[] result = new int[k]; for (int i = k - 1; i >= 0; i--) { result[i] = pq.poll()[0]; } return result; } }
http://www.cnnetsun.cn/news/41310.html

相关文章:

  • System Informer 终极指南:从零掌握Windows系统监控神器
  • 20、集群节点与实例的添加和删除操作指南
  • 5大React动画库生态对比:从入门到精通的全栈解决方案
  • 2、Oracle Real Application Clusters (RAC):特性、成本与效益解析
  • Phi-2模型完全攻略:让27亿参数的小巨人成为你的AI助手
  • 30分钟掌握Tauri:用Rust构建你的第一个桌面应用
  • WeChatTweak-macOS开源项目深度参与指南
  • NootRX:让AMD RDNA 2显卡在macOS上完美运行
  • DBeaver崩溃救星:3步紧急恢复SQL脚本的完整方案
  • 项目效率翻倍,做对了什么?
  • 少儿编程考试路径规划:考级与竞赛时间如何平衡?
  • 火星漫游车Rocker-Bogie悬挂系统核心技术深度解析与实战指南
  • ImmortalWrt网络流量监控完全指南:快速排查网络异常与优化带宽分配
  • 青少年编程考级的三大核心价值:目标建立与能力提升
  • 大疆(DJI)前端开发岗位面试经验总结与备战指南
  • AI难?看涂鸦智能、Lark和德勤中国如何借亚马逊云科技突围
  • Kimi-K2-Instruct模型部署指南:从快速入门到生产级优化
  • 企业级系统监控UI架构设计与性能优化实战
  • 多模态智能体如何重塑人机交互:UI-TARS-1.5的三大技术突破与应用前景
  • 快速排序:10分钟掌握高效算法精髓
  • windows著名漏洞——Zerologon(零登录)
  • 6、技术写作风格与在线文档写作指南
  • 文章查重率超出限制?五个步骤轻松降低至安全线
  • 12、技术文档创作与信息管理全解析
  • 9大AI论文平台对比:智能生成开题框架与完整论文内容
  • 学术写作利器:9款AI工具测评,精准生成开题报告与论文初稿
  • 20、文档制作全流程指南
  • GPT-20B无限制版:本地部署大模型的技术革命与实战指南
  • MPK(Mirage Persistent Kernel)源码笔记(4)--- 转译系统
  • 中国地形数据完整指南:5分钟快速上手ArcGIS地形分析