数据结构与算法-栈与队列

day12

leetcode 239. 滑动窗口最大值

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

暴力破解:每运动一次都遍历窗口里面的数字...显然不现实。

最小栈思路:

用最小栈作为窗口:由栈尾到栈口的元素是依次减小(或相等)的

当栈每一次滑动的时候,都会进入一个元素m,对m进行判断处理:当m小于等于栈口元素就直接将其添加到栈中当m大于栈口元素时,循环将栈口元素弹出,直到栈口元素大于m或栈为空,当窗口的元素个数等于k个后栈尾的元素为当前窗口的最大值。

当栈的元素等于k后,每次滑动还要弹出栈尾的一个元素,但是为了维护最小栈,栈内的元素可能不足k个,这时我们可以使用判断当前栈尾的元素是否为当前加入元素索引的前k个索引元素,如果是就先将其弹出,在进行加入元素操作。

模拟:
输入:nums = [1,3,3,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                   栈内元素              最大值
[1 ] 3  -1 -3  5  3  6  7      [1]
[1 3 ] -1  -3 5  3  6  7       [3]
[1  3  -1] -3  5  3  6  7      [3 -1]                  3           
 1 [3  -1  -3] 5  3  6  7      [3 -1 -3]               3
 1  3 [-1  -3  5] 3  6  7      [5]                     5
 1  3  -1 [-3  5  3] 6  7      [5 3]                   5
 1  3  -1  -3 [5  3  6] 7      [6]                     6
 1  3  -1  -3  5 [3  6  7]     [7]                     7

当新加入一个元素m的时候:

如果比栈口的元素大,那么就可以将栈口元素弹出,因为m一定比栈口的元素索引靠后,也可以说有m在,栈口比其小的元素都不可能是窗口最大元素

如果比栈口的元素小或等于栈口元素,我们可以直接添加到栈中,因为虽然m小或等于,但是其索引靠后,可能当栈口元素因为窗口大小而弹出栈的后,m就是最大的元素。

当弹出一个元素m的时候: 

因为最小栈原理:由上面的加入元素可知,栈尾到栈口的元素一定是索引有小到大,元素有大到小,所以判断当前加入元素的前个元素m是否为栈尾元素,如果是就弹出,如果不是说明在当前窗口内有比m更大的元素n,在n加入到栈时就将m给弹出了。

代码实现
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        LinkedList<Integer> minList = new LinkedList<>();
        int len = nums.length;
        int[] res = new int[len-k+1];
        int index = 0;
        //处理窗口内元素不足k个
        for(int i = 0; i < k; i++){
            while(!minList.isEmpty() && minList.peekLast() < nums[i]){
                minList.pollLast();
            } 
            minList.add(nums[i]);
        }
        res[index++] = minList.peekFirst();
        int pre = k;
        while(k < len){
            //弹出元素
            if(minList.peekFirst() == nums[k - pre]) minList.pollFirst();
            while(!minList.isEmpty() && minList.peekLast() < nums[k]){
               minList.pollLast();
            } 
            minList.add(nums[k]);
            res[index++] = minList.peekFirst();
            k++;
        }
        return res;
    }
}

leetcode 347. 前 K 个高频元素

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

思路:使用哈希表存储数组内不同数字的出现个数

使用int数组类型优先级队列:队列存储的数组存有两个元素,第一个为数组内的数字,第二个为该数字出现的次数,优先队列的排序规则为数字出现次数越多的越靠后

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        Queue<int[]> queue = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]);
        for (int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            if(queue.size() == k){
                int[] remove = queue.remove();
                if(entry.getValue() > remove[1]){
                    queue.add(new int[]{entry.getKey(),entry.getValue()});
                }else{
                    queue.add(remove);
                }
            }else{
                queue.add(new int[]{entry.getKey(), entry.getValue()});
            }
        }
        int[] res = new int[k--];
        for (int[] ints : queue) {
            res[k--] = ints[0];
        }
        return res;
    }
}
  • 14
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值