算法修炼Day13|239. 滑动窗口最大值 ● 347.前 K 个高频元素

98 阅读2分钟

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

1.思路

滑动窗口,暴力解法(超时) 双端队列,记录区间内最大值的索引,将索引对应的元素加入结果数组中,返回结果即可.

2.代码实现
// 暴力解法
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int maxcount = -100000;
        int[] res = new int[nums.length-k+1];
        int count = 0;
        for (int i = 0; i < nums.length-k+1; i++) {
            for (int j = i; j < i + k; j++) {
                maxcount= Math.max(maxcount, nums[j]);
            }
            res[count++] = maxcount;
            maxcount = -100000;
        }
        return res;
    }
}
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        // 使用双端队列来存储滑动窗口中的元素索引
        ArrayDeque<Integer> deque = new ArrayDeque<>();
        int n = nums.length;
        // 结果数组的长度为 n - k + 1
        int[] res = new int[n - k + 1];
        int idx = 0; // 结果数组的索引
        for (int i = 0; i < n; i++) {
            // 移除队列中已经不在滑动窗口范围内的元素
            while (!deque.isEmpty() && deque.peek() < i - k + 1) {
                deque.poll();
            }
            // 移除队列中比当前元素小的元素
            while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
                deque.pollLast();
            }
            deque.offer(i); // 将当前元素索引加入队列
            if (i >= k - 1) { // 当窗口的大小达到 k 时
                res[idx++] = nums[deque.peek()]; // 将队列中的最大元素加入结果数组
            }
        }
        return res; // 返回结果数组
    }
}
3.复杂度分析

时间复杂度:O(n).

空间复杂度:O(k).

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

1.思路

使用map 中key-value结构做映射,value记录频率。 借助优先级队列,对其进行排序,维护频率前k高的元素。

2.代码实现
class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        // 创建一个优先队列,按照频率升序排序
        PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]);
        
        // 创建结果数组
        int[] res = new int[k];
        
        // 创建一个 HashMap 来存储元素和其对应的频率
        Map<Integer, Integer> map = new HashMap<>();
        
        // 遍历整数数组,统计元素的频率
        for (int i = 0; i < nums.length; i++) {
            map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
        }
        
        // 遍历 HashMap 中的元素,将元素和频率放入优先队列中
        for (var x : map.entrySet()) {
            int[] tmp = new int[2];
            tmp[0] = x.getKey(); // 元素
            tmp[1] = x.getValue(); // 频率
            pq.offer(tmp);
            
            // 如果优先队列的大小超过 k,移除频率最小的元素
            if (pq.size() > k) {
                pq.poll();
            }
        }
        
        // 从优先队列中取出前 k 个元素作为结果
        for (int i = 0; i < k; i++) {
            res[i] = pq.poll()[0];
        }
        
        return res;
    }
}
import java.util.*;

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        // 创建一个优先队列,按照频率升序排序
        PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]);
        
        // 创建结果数组
        int[] res = new int[k];
        
        // 创建一个 HashMap 来存储元素和其对应的频率
        Map<Integer, Integer> map = new HashMap<>();
        
        // 遍历整数数组,统计元素的频率
        for (int i = 0; i < nums.length; i++) {
            map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
        }
        
        // 遍历 HashMap 中的元素,将元素和频率放入优先队列中
        Iterator<Map.Entry<Integer, Integer>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer, Integer> entry = iterator.next();
            int[] tmp = new int[2];
            tmp[0] = entry.getKey(); // 元素
            tmp[1] = entry.getValue(); // 频率
            pq.offer(tmp);
            
            // 如果优先队列的大小超过 k,移除频率最小的元素
            if (pq.size() > k) {
                pq.poll();
            }
        }
        
        // 从优先队列中取出前 k 个元素作为结果
        for (int i = 0; i < k; i++) {
            res[i] = pq.poll()[0];
        }
        
        return res;
    }
}

以上代码将增强for循环改为普通for循环,使用迭代器遍历 map 中的元素。在循环中,获取每个元素的键和值,并将它们放入优先队列 pq 中。如果优先队列的大小超过 k,移除频率最小的元素。最后,从优先队列中取出前 k 个元素作为结果数组 res 返回。

3.复杂度分析

时间复杂度:O(n).

空间复杂度:O(k).