LeetCode 239. Sliding Window Maximum
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 k numbers in the window. Each time the sliding window moves right by one position.
題意:給你一個數組nums,有一個大小為k的滑動視窗從陣列的最左移動到最右。你只能看到窗口裡的k個數。視窗每次往右邊滑動一個位置。
For example,
Given nums = [1,3,-1,-3,5,3,6,7]
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.
注意:假設k總是有效,如 1 ≤ k ≤ 非空陣列的大小
Follow up:
Could you solve it in linear time?
另外:你能否線上性時間內解決這個問題?
開始的解題思路,從左滑到右,記錄視窗的最大值和最大值的索引:
1. 如果視窗滑動後,該最大值依然在視窗內,且大於視窗最右邊的數,則該最大值依然是視窗的最大值。
2. 否則,重新在視窗內尋找最大值,並記錄最大值的索引。
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if(k == 1 || nums.empty()) return nums;
int maxi = nums[0], iMax = 0; // maxi 記錄當前視窗最大數,iMax記錄最大數的索引
int l = 0, r = k - 1, n = nums.size() - 1; // 視窗左右指標
vector<int> res;
findMax(nums, l, r, maxi, iMax); // 找到第一個視窗的最大數和其索引
res.push_back(maxi);
while(r < n){
++l; ++r;
if(maxi > nums[r] && iMax >= l){ // 移動視窗後,原來最大的數大於視窗最右邊的數,且原來最大的數在視窗內
res.push_back(maxi);
continue;
}
else{ // 原來最大的數不在視窗內
findMax(nums, l , r, maxi, iMax); // 重新找到最大數
res.push_back(maxi);
}
}
return res;
}
private:
// 找到[l, r] 範圍內的最大數和其索引
void findMax(vector<int>& nums, const int& l, const int& r, int& maxi, int& iMax){
if(r >= nums.size()) return;
maxi = nums[l], iMax = l;
for(int i = l + 1; i <= r; ++i){
if(nums[i] > maxi){
maxi = nums[i];
iMax = i;
}
}
}
};
分析時間複雜度和空間複雜度:
Time Complexity:
最壞情況:當陣列降序的時候,會發生最壞情況,每次都需要重新尋找最大值和索引,時間複雜度為O(n * k)
最好情況:[i - ( k - 1), i + k]中的最大值在i處,所以將陣列分成 n / 2k 份,每份重新查詢時間為k,時間複雜度為O( n / 2k * k) = O(n)
Space Complexity:
沒有額外使用空間O(1)
參考討論中的另一種方法,使用deque:
https://leetcode.com/problems/sliding-window-maximum/discuss/65884/Java-O(n)-solution-using-deque-with-explanation
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k)
{
std::deque<int> dq;
std::vector<int> result;
for(int i = 0; i < nums.size(); ++i) {
if(!dq.empty() && dq.front() == i - k) {
dq.pop_front();
}
while(!dq.empty() && nums[dq.back()] < nums[i])
dq.pop_back();
dq.push_back(i);
if(i >= k - 1) {
result.push_back(nums[dq.front()]);
}
}
return result;
}
};
Time Complexity:
對nums中的每一個數進出佇列操作各一次,時間複雜度為O(2*n) = O(n)