给定一个有限数字序列,长度为n,求连续k个(k
看完这个题目,最简单粗暴的方法肯定是用两层for循环:
int maxSum(int arr[], int n, int k){
int curSum = 0;
int maxSum = 0;
for(int i = 0; i <= n - k; i++){
for (int j = i; j < i + k; j++){
curSum += arr[j];
}
if (curSum > maxSum){
maxSum = curSum;
}
curSum = 0;
}
return maxSum;
}
但是显然时间复杂度很高,这里可以采用滑动窗口法来解决这个问题,甚至这一类问题。
如下图,n=8,k=3,即求连续3个数和的最大值。可以想象有一个红色的容量为3个数字的矩形窗口在沿着数字序列滑动,有两个指针right和left分别指向窗口的两端:left指向窗口左端,right指向窗口右端。窗口不断滑动的过程其实就是left++,right++的过程,直至right移至数列末端。
代码示例如下:
int maxSum(int arr[], int n, int k){
int curSum = 0;
int maxSum = 0;
int left = 0;
int right = k - 1;
for (int i = left; i < k; i++){
curSum += arr[i];
}
maxSum = curSum;
while (right < n){
right++;
curSum = curSum + arr[right] - arr[left];
left++;
if (curSum>maxSum){
maxSum = curSum;
}
}
return maxSum;
}
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。
示例: 输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
分析:该题目应用滑动窗口法,需要设置两个指针left和right,把索引闭区间 [left, right] 称为一个「窗口」,其中right指示滑动窗口的右侧,left指示左侧(最后一个元素);curSum记录当前窗口元素的和。接下来分两种情况:
重复上述步骤直至right移至末尾。代码如下:
int minLength(vectorarr, int s)
{
int left = 0;
int right = 0;
int curSum = 0;
int minLen = arr.size()+1;
int curLen = 0;
while (right < arr.size()){
if (curSum + arr[right] < s){
curSum += arr[right];
right++;
}
else{
curLen = right - left + 1;
curSum = curSum - arr[left];
left++;
if (curLen < minLen){
minLen = curLen;
}
}
}
return curLen == 0 ? 0 : minLen;
}
给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。
字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明:字母异位词指字母相同,但排列不同的字符串。
不考虑答案输出的顺序。输入: s: "cbaebabacd" p: "abc"
输出: [0, 6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的字母异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的字母异位词。
分析:同样使用双指针滑动窗口法,本题另一点是判断当前窗口的字母是否是p的异位词的子串,本题采用的方法是用一个长度为26的数组n_p统计p中每个字母出现的次数,然后将当前窗口内的各个字母出现的次数n_s与n_p比较,如果相同,则将left压栈。
vector findAnagrams(string s, string p) {
if (s.length()n_s(26, 0);
vectorn_p(26, 0);
vectorres;
int left = 0;
int right = 0;
for (right = 0; right
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1: 输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2: 输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3: 输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
分析:同样使用双指针滑动窗口法,本题判断是否有重复出现的字母的方法与上一题类似,定义一个长度为256的数组window_arr并全部初始化为0;遍历当前窗口子串,将出现的字母对应的数组位置置为1,移动窗口,如果window_arr[right]==1,说明该字符在之前窗口已经出现过,left++;否则right++,并且长度+1。代码如下:
int lengthOfLongestSubstring(string s) {
int length = s.length();
if (length == 0)
return 0;
int curLength = 0;
int maxLength = 1;
int left = 0;
int right = 0;
int window_arr[256] = {0};
window_arr[s[right]]++;
right++;
while(right < s.length()){
if(window_arr[s[right]]==0){
window_arr[s[right]]++;
right++;
curLength = right-left;
if(curLength>maxLength){
maxLength = curLength;
}
}
else{
window_arr[s[left]]--;
left++;
}
}
return maxLength;
}
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。
示例:
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:滑动窗口的位置 最大值
--------------- -----
[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
分析: 题目点名是滑动窗口,但此题考察点不仅仅是滑动窗口,还要找寻当前滑动窗口里的最大值。找k个数的最大值很简单,哪怕用遍历方法。但是在滑动窗口中需要分两种情况:
代码如下:
int findMax(vector&nums, int left, int right){
int max = nums[left];
for (int i = left + 1; i <= right; i++){
if (nums[i] > max){
max = nums[i];
}
}
return max;
}
vector maxSlidingWindow(vector& nums, int k) {
vectorres;
if (k > nums.size() || nums.size() == 0){
return res;
}
int left = 0;
int right = k - 1;
int curMax = 0;
int subMax = 0;
int i = left;
curMax = findMax(nums, left, right);
res.push_back(curMax);
while (right < nums.size()-1){
right++;
left++;
if (curMax == nums[left-1]){// 上一个窗口的最大值curMax在窗口的最左边
subMax = findMax(nums, left, right);
}
else{ // 上一个窗口的最大值curMax不在窗口的最左边
subMax = curMax;
}
curMax = subMax>nums[right] ? subMax : nums[right];
res.push_back(curMax);
}
return res;
}
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。
示例: 输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:如果 S 中不存这样的子串,则返回空字符串 ""。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
分析:同样,采用双指针滑动窗口法,定义两个指针right和left,并都初始化为0,即字符串S的起始处。定义一个长度为256的数组window_arr来统计字符串T中的元素。如图,right和left移动的关键点分别为:
代码如下:
string minWindow2(string s, string t){
int count[256] = { 0 };
int left = 0;
int right = 0;
int curLen = 0;
int minLen = s.length();
string res = "";
for (int i = 0; i < t.length(); i++){
count[t[i]]++;
}
while (right <= s.length()){
if ((--count[s[right]]) >= 0){
curLen++;
}
while (curLen == t.length()){
if (right - left + 1 <= minLen){
minLen = right - left + 1;
res = s.substr(left, right - left + 1);
}
if (++count[s[left]] > 0){
curLen--;
}
left++;
}
right++;
}
return res;
}