代码随想录算法训练营第十天|150. 逆波兰表达式求值|239. 滑动窗口最大值、347. 前 K 个高频元素

150. 逆波兰表达式求值

题目链接:

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

题目要求:

给你一个字符串数组 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. 滑动窗口最大值

题目链接:

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

题目要求:

给你一个整数数组 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 个高频元素

题目链接:

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

题目要求:

给你一个整数数组 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]+" ");
        }


    }
}

  • 12
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值