1.438. 找到字符串中所有字母异位词
题目描述:
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例:
示例 1:
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
示例 2:
输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
提示:
1 <= s.length, p.length <= 3 * 104
s 和 p 仅包含小写字母
解答描述:
该题要找到s 中所有 p 的 异位词 的子串,注意:异位词 指由相同字母重排列形成的字符串(包括相同的字符串)所以只需要判断s中长度为p.size()的子串中所含元素的种类和个数和p相同即可。
使用长度为p.size()的固定的滑动窗口。
首先,计算出第一个p.size()的s子串的各元素种类和数量,以及p中所有元素的种类和个数。如果相等,将起始位置压入结果。
然后,左边一个元素出窗口且左端点后移一位cnt[s[l]-'a']--,l++,右端点同步后移一位并且右边一个元素入窗口r++,cnt[s[r]-'a]++。
一直判断,直到组不成长度为n的字符串为止。
注意:由于while循环的判断条件是先用l再l++,所以可能会遗漏最后一个长度为p.size()但是满足条件的字符串,特判一下。
代码:
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> ans;
int n1=s.size();
int n2=p.size();
if(n1<n2)
{
return ans;
}
vector<int> cnt1(26,0);//用vector判相等时可以直接==
vector<int> cnt2(26,0);
//先算出p中每个字符出现的次数
for(int i=0;i<n2;i++)
{
cnt2[p[i]-'a']++;
cnt1[s[i]-'a']++;
}
//滑动窗口,大小为n2
int l=0;
int r=n2-1;
while(l<n1-n2)//注意这里的n1-n2 超过这个范围不可能满足题意
{
if(cnt1==cnt2)
{
ans.push_back(l);
}
cnt1[s[l]-'a']--;//左边一个元素出窗口
l++;
r++;
cnt1[s[r]-'a']++;//右边一个元素进窗口
}
if(cnt1==cnt2)//最后一组也满足条件 压入
{
ans.push_back(l);
}
return ans;
}
};
2.713. 乘积小于K的子数组
题目描述:
给定一个正整数数组 nums和整数 k 。
请找出该数组内乘积小于 k 的连续的子数组的个数。
示例:
示例 1:
输入: nums = [10,5,2,6], k = 100
输出: 8
解释: 8个乘积小于100的子数组分别为: [10], [5], [2], [6], [10,5], [5,2], [2,6], [5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于100的子数组。
示例 2:
输入: nums = [1,2,3], k = 0
输出: 0
提示:
1 <= nums.length <= 3 * 104
1 <= nums[i] <= 1000
0 <= k <= 106
解答描述:
该题要找出该数组内乘积小于 k 的连续的子数组的个数。采用窗口不固定的滑动窗口。
首先,令窗口的左右端点都为0,然后对每一个右端点,找到以右端点为结束的最大的满意的条件的长度,寻找的方式是从左端点开始一直连乘,扩展右端点,直到乘积>=k时,移除滑动窗口左端的元素,对于每一个r,【l,r】内的元素都是满足题意的,共有连续子数组个数r-l+1。
代码:
class Solution {
public:
int numSubarrayProductLessThanK(vector<int>& nums, int k) {
int ans=0;
int n=nums.size();
if(k==0 || k==1)//nums数组元素为正整数
{
return ans;
}
//使用窗口大小不固定的滑动窗口
int mul=1;//当前相乘的结果
int l=0;
for(int r=0;r<n;r++)//计算以每个右边界的<k的连续子数组个数
{
mul*=nums[r];//一直乘下去可能会溢出
while(mul>=k)//当mul大于等于k时,考虑窗口左端要移除元素
{
mul/=nums[l];
l++;
}
//滑动窗口内的元素的乘积都不会超过K,且因为要连续,所以组合方式等于元素长度r-l+1种
ans += r - l + 1;
}
return ans;
}
};
3.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
解答描述:
和上一题连乘非常相似,都是窗口大小不固定的滑动窗口。
但是要注意的是,上一题是要找到所有满足条件的,所以是在不满足条件的时候进行窗口移动
而这一题是要找到满足条件的最小长度的,所以要在满足条件的时候移动以求更优的解。
注意:可能会出现遍历完所有的数加起来都没有target大的情况,这种时候需要返回0.
代码:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n=nums.size();
int min_len=INT_MAX;
int sum=0;
//滑动窗口找到每个l开始的大于等于target的最小长度
int l=0;
int r=0;
while(r<n)
{
sum+=nums[r];
while(sum>=target)
{
min_len=min(min_len,r-l+1);
sum-=nums[l++];
}
r++;
}
return min_len==INT_MAX?0:min_len;
}
};
2043

被折叠的 条评论
为什么被折叠?



