`

LeetCode 239 - Sliding Window Maximum

阅读更多

A long array A[] is given to you. There is a sliding window of size w which is moving from the very left of the array to the very right. You can only see the w numbers in the window. Each time the sliding window moves rightwards by one position. Following is an example: The array is [1 3 -1 -3 5 3 6 7], and w is 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


Input: A long array A[], and a window width w
Output: An array B[], B[i] is the maximum value of from A[i] to A[i+w-1]
Requirement: Find a good optimal way to get B[]

Solution

To get maximal of current window, it can take O(w) or O(logw) time. But we also need to keep track of the maximals as window sliding from left to right.
The first thought might be heap.
By maintaining a heap for all numbers in the window can give us a O(nlogw)-time solution, where
  • building up a heap for initial window takes time O(wlogw)
  • when window moves to the next number, each insertion and deletion take time O(logw) and there are n-w moves in total.
  • after updating the heap, findMax only takes time O(1) since we know the top of heap is the largest. 
So, if w << n, the performance of this solution is good, close to O(n); but if w is not that small, say w = n/3 or n/4, the running time goes up to O(nlogn).

All we need is to keep track of the maximals. Do we really need a heap that performs unnecessary sorting for all numbers in the window?
The answer is NO.

We can use a Deque which allow insertions/deletions on both ends. For a Deque implemented by Circular Array/Bufferor Double Linked List, the basic insert/delete operations run in constant time.

Back to the problem.

What shall we keep in the deque?
If we keep all numbers in the window into the queue, each time when we insert a new number and remove a old one, we need to figure out where to insert so as to maintain the numbers in order. That's not easy...

Actually, we do not need to keep all numbers. For example, suppose numbers in a window of size 4 are

[1, 3, -1, 2], ...

Obviously, no matter what next numbers are, 1 and -1 are never going to be a maximal as the window moving. The queue should look like [3, 2] in this case.

So, to maintain the queue in order,

  • When moves to a new number, iterate through back of the queue, removes all numbers that are not greater than the new one, and then insert the new one to the back.
  • findMax only need to take the first one of the queue.
  • To remove a number outside the window, only compare whether the current index is greater than the front of queue. If so, remove it.
By doing these, we guarantee that the first element of the queue is the maximal and all numbers following it are smaller and came later then it. That said, findMax runs in constant time. Noticing that we only insert and delete each number once. Assuming the insert/delete operations of the Deque run in O(1) time, the total running time for this algorithm is O(n) and it takes at most O(w) space!
/*  
  * Given an array of numbers and a sliding window, find out the maximal  
  * number within the window as its moving.  
  * @param nums the array of numbers.  
  * @param window the size of the sliding window.  
  * @return an array of window maximals, i.e. B[i] is the maximal of A[i, i+w).  
  */  
 public int[] windowMax(int[] nums, int window) {  
   int w = (nums.length < window) ? nums.length : window;  
   // A deque allows insertion/deletion on both ends.  
   // Maintain the first as the index of maximal of the window  
   // and elements after it are all smaller and came later than the first.  
   Deque<Integer> que = new ArrayDeque<Integer>();  
   
   // initialize window  
   int i=0;  
   while (i<w) {  
     while (!que.isEmpty() && nums[que.getLast()] <= nums[i]) {  
       que.removeLast();  
     }  
     que.addLast(i++);  
   }  
   
   // sliding window  
   int[] max = new int[nums.length - w + 1];  
   max[i-w] = num[que.getFirst()];  
   while (i<nums.length) {  
     // add new element  
     while (!que.isEmpty() && nums[que.getLast()] <= nums[i]) {  
       que.removeLast();  
     }  
     que.addLast(i);  
     // remove old element if still in que  
     if (!que.isEmpty() && i-w >= que.getFirst()) {  
       que.removeFirst();  
     }  
     // get maximal  
     ++i;  
     max[i-w] = num[que.getFirst()];  
   }  
   
   return max;  
 } 
我又重构了下代码:
public int[] slidingMax(int[] A, int w) {
	int n = A.length;
	w = Math.min(n, w);
	int k = n - w + 1;
	int[] max = new int[k];
	Deque<Integer> deq = new ArrayDeque<>();
	for(int i=0; i<n; i++) {
		while(!deq.isEmpty() && A[deq.getLast()] <= A[i]) {
			deq.removeLast();
		}
		deq.addLast(i);
		if(i < w-1) continue;
		while(!deq.isEmpty() && i-w>=deq.getFirst()) {
			deq.removeFirst();
		}
max[i-w+1] = A[deq.getFirst()];
	}
	return max;
}
 
 
分享到:
评论

相关推荐

    c语言-leetcode题解之0239-sliding-window-maximum

    c c语言_leetcode题解之0239_sliding_window_maximum

    leetcode信封-LeetCode:LeetCode解题

    leetcode信封 LeetCode LeetCode解题 源码目录 //main下为源码,test下为单元测试 │ src │ ├─main │ └─java │ └─com │ └─algorithm ...SlidingWindowMaximum.java //239. Sliding Window Maximum

    leetcode题库-Leetcode-Summary:Leetcode刷题总结(Java版)——更新中

      滑动窗口的最大值(Maximum_value_of_sliding_window.java)   包含min函数的栈(The_stack_containing_the_min_function.java)   队列的最大值(The_maximum_value_of_the_queue.java) 堆(heap_items) ...

    leetcode卡-leetcode_practices_learncard_hashtable:我的leetcode哈希表学习卡实践

    6. **滑动窗口最大值/最小值**:“滑动窗口最大值”(Sliding Window Maximum),使用双端队列和哈希表可以高效地找到每个窗口内的最大值。 7. **组合优化问题**:如“组合总和”(Combination Sum),哈希表可以...

    LeetCode最全代码

    318| [Maximum Product of Word Lengths](https://leetcode.com/problems/maximum-product-of-word-lengths/) | [C++](./C++/maximum-product-of-word-lengths.cpp) [Python](./Python/maximum-product-of-word-...

    lrucacheleetcode-leetcode:leetcode

    Maximum 255. Verify Preorder Sequence in Binary Search Tree 907. Sum of Subarray Minimums 二叉搜索树 99. Recover Binary Search Tree 109. Convert Sorted List to Binary Search Tree 116. Populating Next ...

    leetcode双人赛-LeetCode:力码

    leetcode双人赛 1. Pattern: Sliding Window,滑动窗口类型 滑动窗口类型的题目经常是用来执行数组或是链表上某个区间(窗口)上的操作。比如找最长的全为1的子数组长度。滑动窗口一般从第一个元素开始,一直往右边...

    算法面试通关40讲完整课件 11-13 优先队列(PriorityQueue)

    - 滑动窗口最大值:在滑动窗口内维护一个最大值,如LeetCode题目《Sliding Window Maximum》。 - Dijkstra最短路径算法:用于寻找图中节点间的最短路径。 - Huffman编码:在数据压缩中构建最优的Huffman树。 5. ...

    Leetcode-practice

    LeetCode中的回溯法(Backtracking)和滑动窗口最大值(Sliding Window Maximum)等题目的解决方案常涉及栈和队列。 4. 哈希表:哈希表是一种通过键值对进行高效查找的数据结构。Java中的HashMap类提供了快速的插入...

    leetcode代码200题c++

    5. **Sliding Window Maximum**:这是一个滑动窗口最大值问题,要求在不断移动窗口时,找到每个窗口内的最大值。可以使用单调栈或双端队列(deque)来解决。 6. **Factorial Trailing Zeroes**:该问题涉及到数学...

    Leetcode

    例如,"滑动窗口最大值"(Sliding Window Maximum)需要找出数组中每个指定宽度窗口的最大值。 5. **哈希表**:哈希表提供了快速查找功能,常见于解决查找、计数、去重等问题。"两数之和"(Two Sum)也可以用哈希表...

    leetcode_blog

    而“Sliding Window Maximum”问题则需要我们理解队列的特性,找出数组中每个固定窗口大小的最大值。 二叉树问题在LeetCode中占据了相当大的比重,如“Binary Tree Inorder Traversal”要求中序遍历二叉树。学习...

    春节7天练丨Day2:栈、队列和递归1

    2. **Sliding Window Maximum**:找到数组中每个滑动窗口的最大值,可以使用队列来快速找到每个窗口的最大值。 ### 递归 递归是一种解决问题的方法,它通过调用自身来解决问题。递归通常用于解决树形结构的问题、...

Global site tag (gtag.js) - Google Analytics