代码随想录刷题笔记-Day11

1. 逆波兰表达式求值

150. 逆波兰表达式求值icon-default.png?t=N7T8https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/

给你一个字符串数组 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

 解题思路

这是一个后缀表达式的计算问题,后缀表达式是依靠栈进行计算的,数字就入栈,遇到运算符就出栈两次进行计算,计算后的值重新入栈。

边界值分析:

除法向0截断,也就是说不考虑小数;不含除0运算,可以不进行相应的if判断;32位整数表示,使用int类型就够了。

代码

class Solution {
    public int evalRPN(String[] tokens) {
        Deque stack = new LinkedList<>();
        for (String token : tokens) {
            if ("+".equals(token)) {
                stack.push(stack.pop() + stack.pop());
            } else if ("-".equals(token)) {
                stack.push(-stack.pop() + stack.pop());
            } else if ("*".equals(token)) {
                stack.push(stack.pop() * stack.pop());
            } else if ("/".equals(token)) {
                int temp = stack.pop();
                stack.push(stack.pop() / temp);
            } else {
                stack.push(Integer.valueOf(token));
            }
        }
        return stack.pop();
    }
}

2. 滑动窗口最大值

239. 滑动窗口最大值icon-default.png?t=N7T8https://leetcode.cn/problems/sliding-window-maximum/description/

给你一个整数数组 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]

解题思路

需要找到一个滑动窗口每一个时刻的最大值,滑动窗口这种对首尾进行操作,不对中间进行操作,很适合队列。并且,只需要滑动窗口的最大值,所以不用在队列中维护全部的数。那么究竟需要维护多少呢,一个max,一个第二大的值second。要保证当最大值被弹出后,我依旧能够知道剩余部分的最大值是多少。

所以对于每一个值add进去的时候,把小于等于nums[i]的数全都弹出来。队列变成了一个单调队列。每次peek就是最大值。新加入的问题解决了,新弹出的问题不好解决。因为单纯的值是无法定位位置的,我无法感知到我这个最大值是不是应该到了要弹出的时间。

是不是要弹出取决于数组索引,而由数组索引可以得到值,所以改为存数组索引在队列内,比较的时候还是比较索引位置的值。

代码

class Solution {
	public int[] maxSlidingWindow(int[] nums, int k) {
		Deque queue = new LinkedList<>();
		int[] max = new int[nums.length - k + 1];

		int index = 0;
		for (int i = 0; i < nums.length; i++) {
			if(!queue.isEmpty()&&queue.peek()= k - 1) {
				max[index++] = nums[queue.peek()];
			}
		}

		return max;
	}
}

3. 前 K 个高频元素

347.前 K 个高频元素icon-default.png?t=N7T8https://leetcode.cn/problems/top-k-frequent-elements/给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

输入: nums = [1], k = 1
输出: [1]

解题思路

对于一个算法题的思考,不能够完完全全的陷入到问题本身,包括写业务代码也一样。需要进行抽象,抽象的能力很重要,要把一个东西抽象出一些关键的部分。

这道题,找出频率最高的前k个元素,涉及到频率,还涉及到数据本身,还有频率的排序,需要遍历,遍历途中需要记录频率,所以需要哈希表,最后还涉及到排序。

现在问题的关键在于排序的选择上了,因为题目只要求前k个,所以全部进行排序一定不是最优的。有没有什么办法只取前k个呢?答案是堆。

大根堆无法只维持k个,还是需要维持n个,小根堆可以满足需求。对于超过k个之后的元素,如果需要加入就弹出堆头。

代码

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map map = new HashMap<>();

        PriorityQueue queue = new PriorityQueue<>((o1, o2) -> {
            return o1[1] - o2[1];
        });
        int[] res = new int[k];

        for (int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }

        map.forEach((key, value) -> {
            if (queue.size() < k) {
                queue.add(new int[] { key, value });
            } else {
                if (queue.peek()[1] < value) {
                    queue.poll();
                    queue.add(new int[] { key, value });
                }
            }
        });

        for (int i = k - 1; i >= 0; i--) {
            res[i] = queue.poll()[0];
        }
        return res;
    }
}

你可能感兴趣的:(代码随想录,笔记,算法,java)