You are given an array of integers 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 k
numbers in the window. Each time the sliding window moves right by one position.
Return the max sliding window.
Solutions:
(1) use a deque to save the index of all possible max, with current largest max in the window on the peek
To keep the largest on the peek, we pull when the index is out of range and we save each element after removing the prviously added elemnts which are smaller than the current.
Java:
public int[] maxSlidingWindow(int[] a, int k) {
if (a == null || k <= 0) {
return new int[0];
}
int n = a.length;
int[] r = new int[n-k+1];
int ri = 0;
// store index
Deque<Integer> q = new ArrayDeque<>();
for (int i = 0; i < a.length; i++) {
// remove numbers out of range k
while (!q.isEmpty() && q.peek() < i - k + 1) {
q.poll();
}
// remove smaller numbers in k range as they are useless
while (!q.isEmpty() && a[q.peekLast()] < a[i]) {
q.pollLast();
}
// q contains index... r contains content
q.offer(i);
if (i >= k - 1) {
r[ri++] = a[q.peek()];
}
}
return r;
}
// https://leetcode.com/problems/sliding-window-maximum/discuss/65884/Java-O(n)-solution-using-deque-with-explanation
(2) partition array in the blocks , solve by sliding-max(i) = max{right_max(i), left_max(i+w-1)}
Java:
public static int[] slidingWindowMax(final int[] in, final int w) {
final int[] max_left = new int[in.length];
final int[] max_right = new int[in.length];
max_left[0] = in[0];
max_right[in.length - 1] = in[in.length - 1];
for (int i = 1; i < in.length; i++) {
max_left[i] = (i % w == 0) ? in[i] : Math.max(max_left[i - 1], in[i]);
final int j = in.length - i - 1;
max_right[j] = (j % w == 0) ? in[j] : Math.max(max_right[j + 1], in[j]);
}
final int[] sliding_max = new int[in.length - w + 1];
for (int i = 0, j = 0; i + w <= in.length; i++) {
sliding_max[j++] = Math.max(max_right[i], max_left[i + w - 1]);
}
return sliding_max;
}
// https://leetcode.com/problems/sliding-window-maximum/discuss/65881/O(n)-solution-in-Java-with-two-simple-pass-in-the-array
(3) monotonic queue class
save the <value, counts of elements that were deleted before it and the one before it> in the deque
push: push an element after pop_back() all the elements before if they are small [same in solution (1)] and count the number of deleted numbers; O(1) (amortized)
pop: pop an element out of the queue and if the counts if larger than 0, --; O(1) (pop = remove, it can't report this element)
max: report the max element in queue;O(1)
Time: O(n)
C++:
class Monoqueue
{
deque<pair<int, int>> m_deque; //pair.first: the actual value,
//pair.second: how many elements were deleted between it and the one before it.
public:
void push(int val)
{
int count = 0;
while(!m_deque.empty() && m_deque.back().first < val)
{
count += m_deque.back().second + 1;
m_deque.pop_back();
}
m_deque.emplace_back(val, count);
};
int max()
{
return m_deque.front().first;
}
void pop ()
{
if (m_deque.front().second > 0)
{
m_deque.front().second --;
return;
}
m_deque.pop_front();
}
};
struct Solution {
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> results;
Monoqueue mq;
k = min(k, (int)nums.size());
int i = 0;
for (;i < k - 1; ++i) //push first k - 1 numbers;
{
mq.push(nums[i]);
}
for (; i < nums.size(); ++i)
{
mq.push(nums[i]); // push a new element to queue;
results.push_back(mq.max()); // report the current max in queue;
mq.pop(); // pop first element in queue;
}
return results;
}
};
// https://leetcode.com/problems/sliding-window-maximum/discuss/65885/This-is-a-typical-monotonic-queue-problem