代码随想录算法训练营第十二天| 239. 滑动窗口最大值、347.前 K 个高频元素

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 

        本题一开始我使用的暴力解法,窗口里的值一发生变化就遍历一次窗口找最大值。提交后超时了,看了下超时的数据,窗口长度有1000多,遂思考解决办法。

        窗口里其实我们只关心最大值,以及最大值出队之后下一个值是什么。我们构想一个数据结构,基于队列,队首至队尾从大到小排列,这样能保证队首一直是窗口里的最大值。基于这个构想,我们思考插入规则。

        插入规则:当数A进入窗口队列时,窗口队列中比A小的数其实就没有意义了,因为A既大于他们,又比他们后从窗口队列中出队,最大值不可能取到这些比A小的值,所以,A入队时,直接将比A小的数全部从队尾出队。这样就保证了队列从大到小的顺序。现在我们再来思考窗口队列的出队规则。

public class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        LinkedList<Integer> queue = new LinkedList<>();
        LinkedList<Integer> indexs = new LinkedList<>();
        int [] result = new int[nums.length - k + 1];
        int resultIndex = 0;
        int maxMark;
        for (int i = 0; i < nums.length; i++) {
            while (!queue.isEmpty() && queue.peekLast() < nums[i]){
                queue.removeLast();
                indexs.removeLast();
            }
            queue.addLast(nums[i]);
            indexs.addLast(i);
            if(i - indexs.getFirst() >= k){
                queue.removeFirst();
                indexs.removeFirst();
            }
            if (i >= k-1){
                maxMark = queue.getFirst();
                result[resultIndex++] = maxMark;
            }
        }
        return result;
    }
}

代码有优化空间,没必要用两个队列,用一个队列只存储index就行了,index即包含了位置信息,也包含了具体的值。

347.前 K 个高频元素

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例 1:

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

示例 2:

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

        这题没什么好说的,首先遍历原数组,统计次数,然后再在其中找出最大的K个数。难处理的点主要在于找出最大的前K个数。

比较容易想到的方法有:

1、排序取前K个数

2、构建大顶堆

偷懒用队列排了,也通过了

public class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int a:nums
             ) {
            if (!map.containsKey(a)) map.put(a, 1);
            else {
                map.put(a, map.get(a) + 1);
            }
        }
        LinkedList<Integer> queue = new LinkedList<>();
        LinkedList<Integer> back = new LinkedList<>();
        for (int a:map.keySet()
             ) {
            while (!queue.isEmpty() && map.get(queue.peekLast()) <= map.get(a)){
                int rm = queue.removeLast();
                back.addLast(rm);
            }
            if(queue.size() < k) queue.addLast(a);
            while (!back.isEmpty() && queue.size() != k){
                int rm = back.removeLast();
                queue.addLast(rm);
            }
        }
        int[] result = new int[k];
        for (int i = 0; i < k; i++) {
            result[i] = queue.removeLast();
        }
        return result;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值