题目来源:https://leetcode-cn.com/problems/minimum-size-subarray-sum/
题目描述
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 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(nlog(n)) 时间复杂度的解法。
题目大意
- 找一个不含有重复字符的最长字串,使用一个记录出现次数的cnt数组,通过滑动窗口+双指针的形式即可
滑动窗口+双指针
- 维护一个可变长的窗口,不断地移动左右指针,取最长的窗口长度
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int len = nums.size(), left = 0, right = 0;
int ans = INT_MAX, cnt = 0;
bool flag = false;
for(; right < len ; ++right){
cnt += nums[right];
while(cnt >= target){
ans = min(ans, right - left + 1);
cnt -= nums[left];
++left;
flag = true;
}
}
if(!flag) return 0;
return ans;
}
};
复杂度分析
- 时间复杂度:O(n)。左右指针均移动了n次
- 空间复杂度:O(1)
前缀和+二分查找
- 虽说滑动窗口复杂度是O(n),进阶题目却要nlogn,别问,问就是O(nlogn)有可能优于O(n),想到logn可以联想到在有序数组的条件下,进行二分查找元素的时间复杂度为O(logn),让数组有序的方法,一种是直接进行排序,一种是通过前缀和构造单调序列,题目中的元素值必定为正数,所以前缀和一定是单调序列
- 其中sum[i]表示从nums[0]到nums[i - 1]的元素和。得到前缀和之后,对于每个开始下标i,可通过二分查找sum[i, bound]从i到bound的累加和(也即是i到bound的连续子数组的累加和),如果找到满足sum[i,bound]>=target,更新子数组的最短长度(此时子数组的长度为bound - i + 1)
- 此处可以直接调用stl封装好的
lower_bound
对vector直接进行二分查找计算(面试的时候八成不给直接调用),此处手动实现返回第一个大于等于target的元素对应的下标值index
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int len = nums.size(), ans = INT_MAX;
int sums[len + 1];
sums[0] = nums[0];
// sums[0] = 0 意味着前 0 个元素的前缀和为 0
// sums[1] = A[0] 前 1 个元素的前缀和为 A[0]
for(int i = 1 ; i <= len ; ++i) sums[i] = sums[i - 1] + nums[i - 1];
for(int i = 1 ; i <= len ; ++i){
int newTarget = target + sums[i - 1];
int bound = BinarySearch(newTarget, sums, 0, len);
if(bound != -1){
ans = min(ans, bound - i + 1);
}
}
return ans == INT_MAX ? 0 : ans;
}
int BinarySearch(int target, int* nums, int left, int right){
while(left <= right){
int mid = right + ((left - right) >> 1);
if(nums[mid] < target) left = mid + 1;
else{
if(mid == 1 || nums[mid - 1] < target) return mid;
else right = mid - 1;
}
}
return -1;
}
};
复杂度分析
- 时间复杂度:O(nlogn)。n为数组的长度,n次循环 * logn为二分查找的平均复杂度
- 空间复杂度:O(n)。n为数组的长度,维护一个前缀和数组