150. 逆波兰表达式求值
题目链接:
题目要求:
给你一个字符串数组 tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
注意:
- 有效的算符为
'+'
、'-'
、'*'
和'/'
。 - 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
- 两个整数之间的除法总是 向零截断 。
- 表达式中不含除零运算。
- 输入是一个根据逆波兰表示法表示的算术表达式。
- 答案及所有中间计算结果可以用 32 位 整数表示。
题目用例:
示例 1:
输入:tokens = ["2","1","+","3","*"] 输出:9 解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入:tokens = ["4","13","5","/","+"] 输出:6 解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:
输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"] 输出:22 解释:该算式转化为常见的中缀算术表达式为: ((10 * (6 / ((9 + 3) * -11))) + 17) + 5 = ((10 * (6 / (12 * -11))) + 17) + 5 = ((10 * (6 / -132)) + 17) + 5 = ((10 * 0) + 17) + 5 = (0 + 17) + 5 = 17 + 5 = 22
实现思路:
1. 创建栈(stack)
2. 遍历字符串数组
3. 判断当前字符串是否为运算符
4.判断栈是否为空,令:num2 = stack.pop();num1 = stack.pop();
5. 计算并压栈:根据运算符进行相应的计算,并将结果压回栈中。
加法:num1 + num2
减法:num1 - num2
乘法:num1 * num2
除法:num1 / num2(
6. 处理非运算符:如果当前遍历到的字符串token不是运算符,那么它一定是一个操作数(整数)。将这个字符串转换为整数,并压入栈中。
7. 返回结果(stack.pop())
实现代码:
import java.util.Stack;
class Solution {
/* 给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
注意:
有效的算符为 '+'、'-'、'*' 和 '/' 。
每个操作数(运算对象)都可以是一个整数或者另一个表达式。
两个整数之间的除法总是 向零截断 。
表达式中不含除零运算。
输入是一个根据逆波兰表示法表示的算术表达式。
答案及所有中间计算结果可以用 32 位 整数表示。*/
public int evalRPN(String[] tokens) {
//创建栈
Stack<Integer> stack = new Stack<>();
//遍历字符串
for (String token : tokens) {
if(token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/")){
if(!stack.isEmpty()){
Integer num2 = stack.pop();
Integer num1 = stack.pop();
switch (token){
case "+":
stack.push(num1 + num2);
break;
case "-":
stack.push(num1 - num2);
break;
case "*":
stack.push(num1 * num2);
break;
case "/":
stack.push(num1 / num2);
break;
}
}
}else {
stack.push(Integer.valueOf(token));
}
}
return stack.pop();
}
}
测试代码:
public class Test {
public static void main(String[] args) {
/* 示例 1:
输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:
输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22*/
Solution solution = new Solution();
//示例1:
String[] tokens01 = {"2","1","+","3","*"};
System.out.println(solution.evalRPN(tokens01));
//示例2:
String[]tokens02 = {"4","13","5","/","+"};
System.out.println(solution.evalRPN(tokens02));
//示例3:
String[] tokens03 ={"10","6","9","3","+","-11","*","/","*","17","+","5","+"};
System.out.println(solution.evalRPN(tokens03));
}
}
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]
实现思路:
1.初始化:
创建一个双端队列deque,用于存储数组元素的索引。
创建一个结果数组res,用于存储每个滑动窗口的最大值。
初始化一个索引index,用于跟踪结果数组中的位置。
2.遍历数组
3.维护队列的单调性:
在将当前索引添加到队列之前,先移除队列中所有超出当前窗口范围的索引(即小于i - k + 1的索引)。
移除队列尾部所有小于当前元素nums[i]的索引对应的元素
将当前索引i添加到队列的尾部。
4.记录最大值:
当窗口内元素个数达到k时(即i >= k - 1),队列的头部索引对应的元素就是当前窗口的最大值,将其添加到结果数组res中,并递增index。
5.返回结果(res)
实现代码:
import java.util.ArrayDeque;
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
// 创建双端队列
ArrayDeque<Integer> deque = new ArrayDeque<>();
// 存储结果的数组
int[] res = new int[nums.length - k + 1];
int index = 0; // 结果数组的下标
// 遍历数组
for (int i = 0; i < nums.length; i++) {
// 移除队列中超出窗口范围的元素
while (!deque.isEmpty() && deque.peekFirst() <= i - k) {
deque.pollFirst();
}
// 移除队列中比当前元素小的元素
while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
deque.pollLast();
}
// 添加当前元素到队列尾部
deque.offer(i);
// 当窗口内元素个数达到k时,开始记录最大值
if (i >= k - 1) {
res[index++] = nums[deque.peekFirst()];
}
}
return res;
}
}
测试代码:
public class Test {
/* 示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
示例 2:
输入:nums = [1], k = 1
输出:[1]
*/public static void main(String[] args) {
Solution solution = new Solution();
// 示例 1
int[] nums1 = {1, 3, -1, -3, 5, 3, 6, 7};
int k1 = 3;
int[] result1 = solution.maxSlidingWindow(nums1, k1);
System.out.println("Example 1 Output:");
for (int num : result1) {
System.out.print(num + " ");
}
// 示例 2
int[] nums2 = {1};
int k2 = 1;
int[] result2 = solution.maxSlidingWindow(nums2, k2);
System.out.println("\nExample 2 Output:");
for (int num : result2) {
System.out.print(num + " ");
}
}
}
347. 前 K 个高频元素
题目链接:
题目要求:
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
题目用例:
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2]
示例 2:
输入: nums = [1], k = 1 输出: [1]
实现思路:
1.初始化数据结构:
创建一个HashMap来存储每个元素及其出现的频率。
创建一个大小为k的PriorityQueue(优先队列,也称为堆)来存储频率最高的k个元素。
2.计算频率:
遍历输入数组nums,对于数组中的每个元素,检查它是否已经在HashMap中。
如果元素已经存在,增加其对应的频率计数。
如果元素不存在,将其添加到HashMap中,并设置频率为1。
3.构建最小堆:
遍历HashMap中的每个键值对(元素和频率)。
对于每个键值对,检查优先队列(最小堆)的大小:
如果堆的大小小于k,直接将当前键值对添加到堆中。
如果堆的大小已经达到k,比较当前元素的频率与堆顶元素的频率(堆顶元素是频率最小的元素):
如果当前元素的频率大于堆顶元素的频率,弹出堆顶元素,并将当前键值对添加到堆中。
4.提取结果:
创建一个大小为k的整数数组res来存储结果。
从最小堆中逐个弹出元素(此时堆中存储的是频率最高的k个元素),并将它们的键(即元素本身)存储到res数组中。
5.返回结果(res)
实现代码:
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
class Solution {
//给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。
public int[] topKFrequent(int[] nums, int k) {
// 创建一个HashMap来记录每个元素出现的频率
Map<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
// 创建一个大小为k的小顶堆,用于存储元素和它们的频率
PriorityQueue<Map.Entry<Integer, Integer>> minHeap = new PriorityQueue<>(
(a, b) -> a.getValue() - b.getValue() // 按照频率升序排序
);
// 遍历HashMap,将元素和它们的频率添加到堆中
// 如果堆的大小小于k,则直接添加;否则,如果当前元素的频率大于堆顶元素的频率,则弹出堆顶元素,并添加当前元素
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (minHeap.size() < k) {
minHeap.offer(entry);
} else if (entry.getValue() > minHeap.peek().getValue()) {
minHeap.poll(); // 弹出堆顶元素(频率最小的元素)
minHeap.offer(entry); // 添加当前元素
}
}
// 将堆中的元素(即频率前k高的元素)放入结果数组中
int[] res = new int[k];
int index = 0;
while (!minHeap.isEmpty()) {
res[index++] = minHeap.poll().getKey();
}
return res;
}
}
测试代码:
public class Test {
/* 示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]*/
public static void main(String[] args) {
Solution solution = new Solution();
//示例1:
int[]nums1={1,1,1,2,2,3};
int[]result1=solution.topKFrequent(nums1,2);
for (int i=0;i<result1.length;i++){
System.out.print(result1[i]+" ");
}
System.out.println();
//示例2:
int[]nums2={1};
int[]result2=solution.topKFrequent(nums1,1);
for (int i=0;i<result2.length;i++){
System.out.print(result2[i]+" ");
}
}
}