解题思路
相较于昨天的每日一题,这道题将数据范围和数组长度扩大了,但是O(n)的时间复杂度无所畏惧。根据题意可知,我们需要找到长度为 k 且满足连续上升的子数组中的最大元素,对于一个长度为n的数组而言,有n-k+1个这样的数组,且是从左往右 “滑动” 的,我们将这样一个长度为k的连续数组称之为窗口。那么就只需要判断每个窗口的是否满足连续上升,具体而言,判断长度为k的窗口是否存在k-1个连续上升对(例如[ 2,3] 是一个连续上升对)。那么是否需要对每个窗口单独遍历进行判断呢?当然不需要这么做,我们可以使用滑动窗口机制,使用一个变量upk记录每个窗口的连续上升对。首先我们对第一个窗口进行遍历,统计连续上升对的数量并保存在upk中;对于剩下的n-k个窗口,我们将窗口右滑一步,并判断:
- 新加进来的元素(窗口最右端)是否和前一个元素构成连续上升对?
- 如果是,说明窗口增加一个连续上升对,再判断窗口最左端的元素是否和前一个元素构成构成连续上升对?
- 如果是,说明窗口又减少了一个连续上升对,upk值保持不变;
- 如果不是,那么窗口总体是增加一个连续上升对,upk值加一;
- 如果不是,说明窗口的连续上升对没有增加,再判断窗口最左端的元素是否和前一个元素构成构成连续上升对?
- 如果是,说明窗口减少了一个连续上升对,upk值减一;
- 如果不是,那么窗口的连续上升对数量不变,upk不做修改。
- 如果是,说明窗口增加一个连续上升对,再判断窗口最左端的元素是否和前一个元素构成构成连续上升对?
对于每个窗口的upk值进行判断,若其值为k-1,那么将窗口最右边的元素插入返回数组中,否则将 -1插入返回数组中。
示例代码
class Solution {
public:
vector<int> resultsArray(vector<int>& nums, int k) {
vector<int> ans;
int n = nums.size();
int upk = 0;
// 统计第一个窗口
for(int i = 1; i < k; i++){
if(nums[i] - nums[i-1] == 1) upk++;
}
if(upk == k-1) ans.push_back(nums[k-1]);
else ans.push_back(-1);
for(int i = k; i < n; i++){
// 判断窗口的连续上升对变化
if((nums[i] - nums[i-1] == 1) && (nums[i-k+1] - nums[i-k] != 1)){
upk++;
}
else if((nums[i] - nums[i-1] != 1) && (nums[i-k+1] - nums[i-k] == 1)){
upk--;
}
if(upk == k-1) ans.push_back(nums[i]);
else ans.push_back(-1);
}
return ans;
}
};