滑动窗口算法
给定一个整型数组和一个数字s,找到数组中的最短连续子数组,使得连续子数组的和sum>=s,返回这个最短连续子数组的长度值
如给定[2,3,1,2,4,3],s=7
答案为[4,3],返回2
第一种解法就是暴力解法,采用双循环来遍历所有的子数组,代码如下
#include<iostream> using namespace std; int GetSubArrayLen(int* Arr,int ArrLen,int Val); int main(void) { int* Array; int ArrLen; cin >> ArrLen; Array = new int[ArrLen]; for (int i = 0; i < ArrLen; ++i) cin >> Array[i]; int Val; cin >> Val; cout << GetSubArrayLen(Array, ArrLen, Val)<<endl; system("pause"); return 0; } int GetSubArrayLen(int* Arr,int ArrLen,int Val) { int Len = 0; int sum = 0; for (int t = 0; t < ArrLen; ++t) sum += Arr[t]; if (sum > Val) Len = ArrLen; else return 0; for(int i=0;i<ArrLen;++i) for (int j = ArrLen - 1; j > i; --j) { sum = 0; for (int t = i; t <= j; ++t) sum += Arr[t]; if(sum>=Val&&((j-i+1)<=ArrLen)) Len=j-i+1; } return Len; }
这种方法的时间复杂度为O(n^3),可以将数组中每个元素的值替换为前面所有数组的和,比如将arr[3]的值变为arr[0]+arr[1]+arr[2]+arr[3],这样求解一段子数组的和时,比如求2~4的子数组之和,就用修改后的arr[4]-arr[2]就可以了,这样可以省去双循环中循环求和步骤门将时间复杂度降到O(n^2)
还有一种滑动窗口方法
连个指针L和R,L表示滑窗的左边框,R表示滑窗的右边框
左边框向右滑动使窗口变小,右边框向右滑动使窗口变大,开始左右边框是重合在一起的,窗口的和就是重合点所在的数
1,先将R向右滑动,当和恰好>=s时,记录下滑窗的子数组长度,如果这个长度小于原来的长度,就更新子数组长度
2,L向右滑动,判断是否仍然>=s,如果满足条件就继续向右滑动
3,如果<s则将R向右滑动,重复1
代码如下
#include<iostream> using namespace std; int GetSubArrayLen(int* Arr,int ArrLen,int Val); int WindowValue(int* Arr, int L, int R); int main(void) { int* Array; int ArrLen; cin >> ArrLen; Array = new int[ArrLen]; for (int i = 0; i < ArrLen; ++i) cin >> Array[i]; int Val; cin >> Val; cout << GetSubArrayLen(Array, ArrLen, Val)<<endl; system("pause"); return 0; } int GetSubArrayLen(int* Arr,int ArrLen,int Val) { int Len = 0; int sum = 0; for (int t = 0; t < ArrLen; ++t) sum += Arr[t]; if (sum > Val) Len = ArrLen; else return 0; int TempLen = 0; int L = 0, R = 0; while (R < ArrLen) { while ((WindowValue(Arr, L, R) < Val)&&(R<ArrLen)) R++; while ((WindowValue(Arr, L, R) >= Val)&&(L<=R)) { TempLen = R - L + 1; if (TempLen <= Len) Len = TempLen; L++; } } return Len; } int WindowValue(int* Arr, int L, int R) { int Sum = 0; for (int i = L; i < R + 1; ++i) Sum += Arr[i]; return Sum; }
leetcode 209
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
提示:
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
进阶:
如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。
class Solution { public: int minSubArrayLen(int target, vector<int>& nums) { int size = nums.size(); if (0 == size) { return 0; } int head = 0, tail = 0; int sum = 0; int len = INT_MAX; while (tail < size) { sum += nums[tail]; while (sum >= target) { len = min(len, tail - head + 1); sum -= nums[head]; ++head; } ++tail; } return len < INT_MAX ? len : 0; } };