Given an array of n
positive integers and a positive integer s
, find the minimal length of a contiguous subarray of which the sum ≥ s
. If there isn’t one, return 0
instead.
Example:
Input: s = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: the subarray [4,3] has the minimal length under the problem constraint.
Follow up: If you have figured out the O(n)
solution, try coding another solution of which the time complexity is O(nlogn)
.
題意:給出一個由正整數組成的長爲 n
的區間,找到最短的連續區間——其區間和滿足 >= s
的條件。
思路1:和之前做過的“紅魔館爆炸了”幾乎一樣,所以一上手就這麼寫了。通過二分搜索長度,然後用固定長度的滑動窗口搜索數組,得到最大的區間和,如果可以滿足 >=s
的條件,則 hi = mid
,因爲要找到的是最短的連續區間;不滿足則 lo = mid + 1
。
代碼1:
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
if (nums.empty()) return 0;
int lo = 0, hi = nums.size();
while (lo < hi) {
int mid = lo + (hi - lo) / 2, maxWin = 0, nowWin = 0;
for (int i = 0; i < nums.size(); ++i) {
if (i < mid) maxWin += nums[i];
else {
//求出固定爲mid長度的區間的最大區間和
nowWin = (i == mid) ? maxWin : nowWin;
nowWin = nowWin + nums[i] - nums[i - mid];
maxWin = max(nowWin, maxWin);
}
} //求出第一個滿足>=s的連續區間長度
if (maxWin >= s) hi = mid;
else lo = mid + 1;
}
if (lo >= nums.size()) {
int sum = 0;
for (int i = 0; i < nums.size(); ++i)
sum += nums[i];
if (sum < s) lo = 0;
}
return lo;
}
};
效率不高,但是能過:
執行用時:24 ms, 在所有 C++ 提交中擊敗了28.25% 的用戶
內存消耗:10.3 MB, 在所有 C++ 提交中擊敗了12.50% 的用戶
思路2:雖然是 ,但是反覆統計區間和浪費了太多的效率,用前綴和優化一下。
代碼2如下:
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
if (nums.empty()) return 0;
int lo = 0, hi = nums.size();
vector<int> preSum(nums.size() + 1, 0);
for (int i = 0; i < nums.size(); ++i) preSum[i + 1] = preSum[i] + nums[i];
while (lo < hi) {
int mid = lo + (hi - lo) / 2, maxWin = 0;
for (int i = mid; i < preSum.size(); ++i)
maxWin = max(preSum[i] - preSum[i - mid], maxWin);
//求出第一個滿足>=s的連續區間長度
if (maxWin >= s) hi = mid;
else lo = mid + 1;
}
if (preSum.back() < s) lo = 0; //整個區間和都無法滿足條件
return lo;
}
};
效率:
執行用時:20 ms, 在所有 C++ 提交中擊敗了45.59% 的用戶
內存消耗:10.4 MB, 在所有 C++ 提交中擊敗了12.50% 的用戶
思路3:前面的滑動窗口都是固定長度的;如果我們允許窗口擴張和收縮,就能得到 的解法。
代碼3:
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
if (nums.empty()) return 0;
int winSum = 0, left = 0, right = 0, minLen = INT_MAX;
while (right < nums.size()) {
winSum += nums[right++]; //right不斷右移
while (winSum >= s) { //滿足條件
minLen = min(minLen, right - left); //修改長度
winSum -= nums[left++]; //區間收縮
}
} //整個區間和都無法滿足條件
return (minLen == INT_MAX) ? 0 : minLen;
}
};
效率:
執行用時:16 ms, 在所有 C++ 提交中擊敗了77.76% 的用戶
內存消耗:10.3 MB, 在所有 C++ 提交中擊敗了12.50% 的用戶
爲什麼內存消耗還是這樣大?不明白。而且似乎沒有優化的地方了,但是還只是擊敗了 77%
的用戶???