第64题——滑动窗口的最大值

356 阅读2分钟

题目:

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。

思路:

  • 常规方法:遍历,从左到右,每次局部再统计最大值,将最大值加入到结果list中,假设num[]数组的长度是m,size大小是n的话,时间复杂度就是O(mn)

  • 利用大根堆,首先创建大根堆heap,大根堆的容量就是size,先加size个数加入到heap中,并将heap堆顶加入到结果list中。然后堆heap删除掉之前第一个进堆的数,后面的数再进堆,将此时堆顶元素加入到list中,循环此步骤。时间复杂度为O(mlogn)

Java

package nowcoder;

import java.util.ArrayList;

public class S64_MaxInWindows {
    public ArrayList<Integer> maxInWindows(int[] num, int size){
        ArrayList<Integer> list = new ArrayList<Integer>();
        if (size <= 0)
            return list;
        int length = num.length;
        for (int i=0;i<length - size+1;i++){
            int j=i;
            int max = 0;
            while (j < i+size){
                if (num[j] > max)
                    max = num[j];
                j++;
            }
            list.add(max);
        }
        return list;
    }
    public static void main(String[] args){
        S64_MaxInWindows s64 = new S64_MaxInWindows();
        int[] num = {10,14,12,11};
        System.out.println(s64.maxInWindows(num, 0));
    }
}

Java,利用堆

package nowcoder;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.PriorityQueue;

public class S64_MaxInWindows_new {
    public ArrayList<Integer> maxInWindows(int[] num, int size){
        //创建大根堆
        PriorityQueue<Integer> heap = new PriorityQueue<Integer>(size, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
        ArrayList<Integer> list = new ArrayList<Integer>();
        if (size <= 0)
            return list;
        int length = num.length;
        for (int i=0;i<size;i++){
            heap.offer(num[i]);
        }
        list.add(heap.peek());
        for (int i=1;i<length-size+1;i++){
            heap.remove(num[i-1]);
            heap.offer(num[i+size-1]);
            list.add(heap.peek());
        }
        return list;
    }
    public static void main(String[] args){
        S64_MaxInWindows_new s64 = new S64_MaxInWindows_new();
        int[] num = {2,3,4,2,6,2,5,1};
        System.out.println(s64.maxInWindows(num, 3));
    }
}

Python 利用双端队列

class MaxInWindows:
    def maxInWindows(self, num, size):
        queue, res, i = [], [], 0
        while size > 0 and i < len(num):
            if len(queue) > 0 and i-size+1 > queue[0]: #若最大值queue[0]位置过期 则弹出
                queue.pop(0)
            while len(queue) > 0 and num[queue[-1]] < num[i]: #每次弹出所有比num[i]小的数字
                queue.pop()
            queue.append(i)
            if i >= size-1:
                res.append(num[queue[0]])
            i += 1
        return res

if __name__ == '__main__':
    test = MaxInWindows()
    num = [2, 3, 4, 2, 6, 2, 5, 1]
    print(test.maxInWindows(num, 3))