算法day10-栈与队列(2)
目录
- 逆波兰表达式求值
- 滑动窗口最大值
- 前K个高频元素
一、逆波兰表达式求值
https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/?envType=problem-list-v2&envId=8At1GmaZ
class Solution { public int evalRPN(String[] tokens) { Deque<String> stack = new ArrayDeque<>(); for(String s : tokens){ if(s.equals("+")){ int n2 = Integer.parseInt(stack.pop()); int n1 = Integer.parseInt(stack.pop()); int sum = n2 + n1; stack.push(String.valueOf(sum)); }else if(s.equals("-")){ int n2 = Integer.parseInt(stack.pop()); int n1 = Integer.parseInt(stack.pop()); int n = n1 - n2; stack.push(String.valueOf(n)); }else if(s.equals("*")){ int n2 = Integer.parseInt(stack.pop()); int n1 = Integer.parseInt(stack.pop()); int n = n1 * n2; stack.push(String.valueOf(n)); }else if(s.equals("/")){ int n2 = Integer.parseInt(stack.pop()); int n1 = Integer.parseInt(stack.pop()); int n = n1 / n2; stack.push(String.valueOf(n)); }else{ stack.push(s); } } return Integer.parseInt(stack.pop()); } }
二、滑动窗口最大值
https://leetcode.cn/problems/sliding-window-maximum/description/?envType=problem-list-v2&envId=8At1GmaZ
方法一:暴力法,直接以3为窗口进行滑动,在每个窗口内都取最大值。
方法二:采用单调队列的方法,始终维护一个单调队列。每个窗口都把最大的元素放在队头,所以每次弹出的也是队头元素,这样可以利用到前面窗口的信息。
class Solution { public int[] maxSlidingWindow(int[] nums, int k) { int n = nums.length; int[] res = new int[n-k+1]; Deque<Integer> queue = new ArrayDeque<>(); int index = 0; for(int i = 0; i<n; i++){ //1.新入队的元素若头节点的索引已经超过以i结尾的窗口的起点,就把头节点去掉 if(!queue.isEmpty() && queue.peek() < i-k+1){ queue.poll(); //把头节点从队头剔除 } while(!queue.isEmpty() && nums[queue.peekLast()] < nums[i]){ queue.pollLast(); //把比新加入的元素小的元素从末尾剔除 } queue.offer(i); if(i >= k-1){ res[index] = nums[queue.peek()]; index++; } } return res; } } //时间复杂度:O(N) //空间复杂度:O(k)
三、前k个高频元素
https://leetcode.cn/problems/top-k-frequent-elements/description/?envType=problem-list-v2&envId=8At1GmaZ
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[]> queue = new PriorityQueue<>((pair1, pair2)->pair2[1] - pair1[1]); //遍历哈希表,把对应的k-v存储到队列中 for(Map.Entry<Integer,Integer> entry : map.entrySet()){ queue.add(new int[]{entry.getKey(), entry.getValue()}); } int[] res = new int[k]; for(int i=0; i<k; i++){ res[i] = queue.poll()[0]; //把key弹出来 } return res; } } //时间复杂度: O(nlogk) //空间复杂度: O(n)
【扩展】数组重的第K个最大元素
https://leetcode.cn/problems/kth-largest-element-in-an-array/description/?envType=problem-list-v2&envId=SrjwzI6W
这道题我们用堆排序来做,主要是熟悉堆排序的流程。
class Solution { public int findKthLargest(int[] nums, int k) { int n = nums.length; int heapSize = n; for(int i = n / 2 - 1; i >= 0; i--){ maxHeapify(nums, i, heapSize); } for(int i = n - 1; i >= n - k + 1; i--){ swap(nums, 0, i); heapSize--; maxHeapify(nums, 0, heapSize); } return nums[0]; } public void maxHeapify(int[] nums, int root, int heapSize){ int left = root * 2 + 1, right = root * 2 + 2; int largest = root; if(left < heapSize && nums[left] > nums[largest]){ largest = left; } if(right < heapSize && nums[right] > nums[largest]){ largest = right; } if(largest != root){ swap(nums, root, largest); maxHeapify(nums, largest, heapSize); } } public void swap(int[] nums, int i, int j){ int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } }