Leetcode 239. Sliding Window Maximum

来源:互联网 发布:不配说爱我dj网络歌手 编辑:程序博客网 时间:2024/05/24 06:14

239. Sliding Window Maximum

Total Accepted: 34347 Total Submissions: 116989 Difficulty: Hard

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the knumbers 

in the window. Each time the sliding window moves right by one position.

For example,
Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.

Window position                Max---------------               -----[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

Therefore, return the max sliding window as [3,3,5,5,6,7].

Note: 
You may assume k is always valid, ie: 1 ≤ k ≤ input array's size for non-empty array.

Follow up:
Could you solve it in linear time?

思路:

一开始说建立一个index数组,长度为nums.length - k + 1,存放对应位置的max结果。然后每当新元素进入,就CHECK与之前max的关系,如果大了直接替换;小的话判断之前的max是不是还合法,合法则该位置结果相同;不合法则说明需要在当前位置重新进行一次寻找。时间复杂度应该是O(nk)吧。其实这个代码是对的,但是没有办法过leetcode的大数据,提示stack overflowed, 应该是递归call太多了。

public class Solution {    public int[] maxSlidingWindow(int[] nums, int k) {        if(nums==null || nums.length==0 || k==1) return nums;                int len = nums.length;        int[] index = new int[len - k + 1];                helper(0, k, nums, index);                int[] res = new int[len - k + 1];        for(int i = 0; i < len - k + 1; i++) res[i] = nums[index[i]];        return res;    }        private void helper(int cur, int len, int[] nums, int[] index){        if(cur == 0) {            index[0] = getCur(0, len, nums);        }else{            int newIn = nums[cur+len-1]; // 新元素            if(newIn >= nums[index[cur-1]])   index[cur] = cur+len-1; // 比之前max大            else if(index[cur-1] < cur)  index[cur] = getCur(cur, len, nums); // 小并检查之前max是否仍然合法,不合法则替换            else index[cur] = index[cur-1]; // 仍合法则当前位置max值不变        }        if(cur + len == nums.length) return;        helper(cur+1, len, nums, index);    }        private int getCur(int pos, int len, int[] nums){        int max = nums[pos], res = pos;        for(int i=pos+1; i<pos+len; i++){            if(max < nums[i]){                res = i;                max = nums[i];            }        }        return res;    }}

网上的答案是简化了这个思路,用一个队列表示现在的k个元素,队列存的是index。每当有一个元素入队,也即窗口移动一次,先把队中比该元素小的删除,之后入队,此时队列内元素大小递减。接下来判断头元素是不是仍然合法,不合法就去除。之后这个头元素就是现位置的结果了。时间 O(N) 空间 O(K)

public class Solution {    public int[] maxSlidingWindow(int[] nums, int k) {        if(k==0 || nums==null) return nums;                int len = nums.length;        int[] res = new int[len - k + 1];        LinkedList<Integer> queue = new LinkedList<Integer>();                for(int i = 0; i < len; i++){            while(!queue.isEmpty() && nums[i] > nums[queue.getLast()]) queue.removeLast();            queue.addLast(i);                        // [i - k + 1, i]            if(queue.getFirst() < i - k + 1) queue.removeFirst();            if(i + 1 - k >=0 ) res[i - k + 1] = nums[queue.getFirst()]; // first k element no place into result        }        return res;    }}


最大堆,时间 O(NlogK) 空间 O(K)。

public class Solution {    public int[] maxSlidingWindow(int[] nums, int k) {        if(nums == null || nums.length == 0) return new int[0];        PriorityQueue<Integer> pq = new PriorityQueue<Integer>(Collections.reverseOrder());        int[] res = new int[nums.length + 1 - k];        for(int i = 0; i < nums.length; i++){            // 把窗口最左边的数去掉            if(i >= k) pq.remove(nums[i - k]);            // 把新的数加入窗口的堆中            pq.offer(nums[i]);            // 堆顶就是窗口的最大值            if(i + 1 >= k) res[i + 1 - k] = pq.peek();        }        return res;    }}


0 0
原创粉丝点击