华为二面之手撕算法:给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值

话不多说,先上题目

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。
例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}
针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个:
{[2,3,4],2,6,2,5,1}{2,[3,4,2],6,2,5,1}{2,3,[4,2,6],2,5,1}{2,3,4,[2,6,2],5,1}{2,3,4,2,[6,2,5],1}{2,3,4,2,6,[2,5,1]}
窗口大于数组长度的时候,返回空。

样例:
输入:[2,3,4,2,6,2,5,1],3
输出:[4,4,6,6,6,5]


方法一

话不多说,上代码

class Solution {
    public int[] allmax(int[] arr, int target) {
	// 滑动窗口大小大于数组长度,返回空
        if (i > arr.length) {
            return null;
        }
	// 计算出滑动窗口的个数
        int[] r = new int[arr.length - i + 1];
	// 用于保存滑动窗口的最大值
        int max = 0;
	// 滑动窗口的头指针
        int f = 0;
	// 滑动窗口的尾指针
        int s = f + i -1;
	// 循环,直到尾指针到达数组尾部
        while (s < arr.length) {
	    // 使用冒泡算法计算出当前滑动窗口里的最大值
            for (int j = f; j <= s; j++) {
                if (arr[j] > max) {
                    max = arr[j];
                }
            }
	    // 保存到结果数组
            r[f] = max;
	    // 将最大值重置
            max = 0;
	    // 头指针向后移动
            f++;
	    // 尾指针向后移动
            s++;
        }
        return r;
    }
}

临时写出来的一个使用双指针移动的方法,这种方法的时间复杂度为O=窗口个数*窗口大小,存在重复比较的问题

方法二

话不多说,再上代码

class Solution {
    public int[] allmax(int[] nums, int k) {
	if(nums == null || nums.length == 0) {
            return new int[0];
        }
        int[] res = new int[nums.length - k + 1];
        Deque<Integer> queue = new ArrayDeque<>();
        for(int i = 0, j = 0; i < nums.length; i++) {
            if(!queue.isEmpty() && i - queue.peek() >= k) {
                queue.poll();
            }
            while(!queue.isEmpty() && nums[i] > nums[queue.peekLast()]) {
                queue.pollLast();
            }
            queue.offer(i);
            if(i >= k - 1) {
                res[j++] = nums[queue.peek()];
            }
        }
        return res;
    }
}
posted @ 2021-08-07 18:29  超级鲨鱼辣椒  阅读(393)  评论(0编辑  收藏  举报