209、长度最小的子数组
本题我尝试了两层循环去解决问题,但是超时了
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int minLen = nums.size() + 1;
for(int i = 0; i < nums.size();i++){
int sumCur = nums[i];
int lenCur = 1;
int j = i+1;
while(sumCur < target && j < nums.size()){
sumCur += nums[j];
j++;
lenCur++;
}
if(sumCur >= target){
if(lenCur < minLen ){
minLen = lenCur;
}
}else{
continue;
}
}
if(minLen <= nums.size()){
return minLen;
}else{
return 0;
}
}
};
观看了代码随想录的讲解,了解到了滑动窗口的概念,这里的关键思路便是:
- 如果当前窗口内总和小于 t a r g e t target target,那么终止位置就需要往后移动,纳入新的值
- 如果当前窗口内总和大于 t a r g e t target target,那么就需要判断是否是最小长度,同时移动起始位置
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT32_MAX;
int sum = 0;
int i = 0;
int subLength = 0;
for( int j = 0; j < nums.size(); j++){
sum += nums[j];
while(sum >= target){
subLength = (j - i + 1);
if(subLength < result){
result = subLength;
}
sum -= nums[i++];
}
}
if(result == INT32_MAX){
return 0;
}else{
return result;
}
}
};
904、水果成篮
这一题的滑动窗口我在更新的时候一直理不清方法,因此也是参考了大佬的代码,用了哈希表来实现:
class Solution {
public:
int totalFruit(vector<int>& fruits) {
unordered_map<int, int> basket;
int maxLen = 0;
int curLen = 0;
int startIndex = 0;
for(int i = 0;i<fruits.size();i++){
basket[fruits[i]]++; // 如果里面有就++,没有创建并++
curLen++;
while(basket.size() > 2){ //如果当前有的大于2了,那么要缩减
basket[fruits[startIndex]]--; //减去当前起始位置的
if(basket[fruits[startIndex]] == 0){ //如果该类等于0就可以删除了
basket.erase(fruits[startIndex]);
}
startIndex++; // 移动,如果还是大于2还要继续减
curLen--;
}
if( maxLen < curLen ){
maxLen = curLen;
}
}
return maxLen;
}
};
76、最小覆盖字串
该题可以用滑动窗口解决,但是难点在于如果判断当前窗口内的子串满足条件,因此字符串 t t t中的字符有可能是重复的。
看了大神的思路,具体为:
-
用一个变量cnt来记录当前滑动窗口的子串中,拥有 t t t中所含有字符的个数
-
用一个哈希表记录 t t t中字符和对应的频数,用另一个哈希表来记录滑动窗口中的字符和对应频数
-
用两个指针 i i i 和 $ j$ 来表示滑动窗口的前后
-
cnt的更新规则:如果 c n t < t . s i z e ( ) cnt < t.size() cnt<t.size() 那么说明此时滑动窗口的子串还没达到要求,那么 i + + i++ i++ ,往后延伸,只有当 w i n F r e q [ s [ i ] ] < = t F r e q [ s [ i ] ] winFreq[s[i]] <= tFreq[s[i]] winFreq[s[i]]<=tFreq[s[i]] 的时候才 c n t + + cnt++ cnt++,因为这样才说明此时未满足要求仍然需要纳入目标字符;只有当 w i n F r e q [ s [ j ] ] > t F r e q [ s [ j ] ] winFreq[s[j]] > tFreq[s[j]] winFreq[s[j]]>tFreq[s[j]] 时,才可以将末尾的字符丢弃,这样仍然能够满足该字符的要求,即对 c n t cnt cnt不做修改。重点就是只要当前的子串中目标字符的个数仍然没够,我们就纳入目标字符并增加cnt,直到子串满足了(即 c n t = = t . s i z e ( ) cnt==t.size() cnt==t.size() ),那么就判断是否是最小,然后将窗口末尾开始收缩。
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char, int> winFreq;
unordered_map<char, int> tFreq;
for(auto c:t){
tFreq[c]++;
}
int cnt = 0;
string result;
for( int i = 0,j = 0; i < s.size(); i++){
winFreq[s[i]]++;
if( winFreq[s[i]] <= tFreq[s[i]]){
cnt++;
}
while(winFreq[s[j]] > tFreq[s[j]]){
winFreq[s[j++]]--;
}
if(cnt == t.size()){
if(result.empty() || i-j+1 < result.size()){
result = s.substr(j,i-j+1);
}
}
}
return result;
}
};