目录
1. 长度最小的数组
class Solution
{
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int sum = 0;
int len = 0;
int right = -1;
int left = -1;
int size = nums.size();
while (right < size)
{
if (sum < target)
{
++right;
if (right < nums.size())
{
sum += nums[right];
}
}
else
{
if (len == 0 || len > right - left)
{
len = right - left;
}
++left;
sum -= nums[left];
}
}
return len;
}
};
class Solution
{
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int count = INT_MAX;
int sum = 0;
for(int right = 0, left = 0; right < nums.size(); right++)
{
sum += nums[right];
while(target <= sum)
{
if(count > right - left + 1)
{
count = right - left + 1;
}
sum -= nums[left++];
}
}
return count == INT_MAX ? 0 : count;
}
};
2. 无重复字符的最长字符串
class Solution
{
public:
int lengthOfLongestSubstring(string s)
{
//简单代替哈希表
int hash[128] = {0};
int left = 0;
int right = 0;
int s_len = 0;
int len = 0;
int size = s.length();
while(right < size)
{
hash[s[right]]++;
len++;
while(hash[s[right]] >= 2)
{
hash[s[left]]--;
left++;
len--;
}
if(s_len < len)
{
s_len = len;
}
right++;
}
return s_len;
}
};
3. 最大连续1的个数
class Solution
{
public:
int longestOnes(vector<int>& nums, int k)
{
int zero = 0;
int ret = 0;
//逻辑执行顺序
//判断,++,计算
//哪里是窗口
for(int right = 0, left = 0; right < nums.size(); right++)
{
if (nums[right] == 0)
{
zero++;
}
while (zero > k)
{
if (nums[left] == 0)
{
zero--;
}
left++;
}
ret = max(right - left + 1, ret);
}
return ret;
}
};
4. 将x减到0的最小操作数
图示:
class Solution
{
public:
int minOperations(vector<int>& nums, int x)
{
//正难则反
//暴力枚举法的优化
int sum = 0;
for(auto e : nums)
{
sum += e;
}
//负数
int target = sum - x;
int reverse_sum = 0;
int count = 0;
if(target < 0)
{
return -1;
}
if(target == 0)
{
return nums.size();
}
for(int left = 0, right = 0; right < nums.size(); right++)
{
reverse_sum += nums[right];
while(reverse_sum > target)
{
reverse_sum -= nums[left];
left++;
}
//区间,左闭右闭
//找最大
if(reverse_sum == target && right - left + 1 > count)
{
cout << right << ' ' << left << endl;
count = right - left + 1;
}
}
return count == 0 ? -1 : nums.size() - count;
}
};
5. 水果成篮
class Solution
{
public:
int totalFruit(vector<int>& fruits)
{
//遍历双指针
//哈希表,种类
int size = fruits.size();
int* hash = (int*)malloc(size * sizeof(int));
memset(hash, 0, size * sizeof(int));
int kind = 0;
int len = 0;
for(int right = 0, left = 0; right < fruits.size(); right++)
{
//进窗口
if(hash[fruits[right]] == 0)
{
kind++;
}
hash[fruits[right]]++;
//出窗口
while(kind > 2)
{
hash[fruits[left]]--;
if(hash[fruits[left]] == 0)
{
kind--;
}
left++;
}
//判断
if(right - left + 1 > len)
{
len = right - left + 1;
}
}
return len;
}
};
6. 找到字符串中所有字母异位词
尝试:
class Solution
{
public:
vector<int> findAnagrams(string s, string p)
{
vector<int> count;
//暴力求解,列出所有长度为字符串p的字串
//进行匹配,哈希表大小26,下标
//记录,判断
int hash[26] = {0};
//所指定下标处都为1
//遍历的指针
for(int right = 0, left = 0; right < s.length(); right++)
{
//进窗口
hash[s[right] - 'a']++;
//出窗口
while(right - left + 1 > p.length())
{
hash[s[left] - 'a']--;
left++;
}
//判断
if(right - left + 1 == p.length())
{
int flag = 1;
for(int i = 0; i < p.length(); i++)
{
//相同的字符
hash[p[i] - 'a']--;
}
for(int i = 0; i < p.length(); i++)
{
if(hash[p[i] - 'a'] != 0)
{
flag = 0;
break;
}
}
for(int i = 0; i < p.length(); i++)
{
hash[p[i] - 'a']++;
}
if(flag)
{
count.push_back(left);
}
}
}
return count;
}
};
优化1:(判断方式改为两个哈希表)
class Solution
{
public:
vector<int> findAnagrams(string s, string p)
{
vector<int> count;
int hash1[26] = {0};
int hash2[26] = {0};
for(int i = 0; i < p.length(); i++)
{
hash2[p[i] - 'a']++;
}
for(int right = 0, left = 0; right < s.length(); right++)
{
//进窗口
hash1[s[right] - 'a']++;
//出窗口
while(right - left + 1 > p.length())
{
hash1[s[left] - 'a']--;
left++;
}
//判断
//两个哈希表
if(right - left + 1 == p.length())
{
int flag = 1;
for(int i = 0; i < 26; i++)
{
if(hash1[i] !=hash2[i])
{
flag = 0;
break;
}
}
if(flag)
{
count.push_back(left);
}
}
}
return count;
}
};
优化2:(计数:判断优化)
class Solution
{
public:
vector<int> findAnagrams(string s, string p)
{
vector<int> ret;
int hash1[26] = {0};
int hash2[26] = {0};
int count1 = 0;
int count2 = 0;
//标记并计算有多少个有效字符
for(int i = 0; i < p.length(); i++)
{
hash2[p[i] - 'a']++;
count2++;
}
for(int right = 0, left = 0; right < s.length(); right++)
{
//有效字符,且没有多余
if(hash2[s[right] - 'a'] && hash1[s[right] - 'a'] < hash2[s[right] - 'a'])
{
count1++;
}
//进窗口
hash1[s[right] - 'a']++;
//出窗口
while(right - left + 1 > p.length())
{
//是有效字符,且出窗口的有效字符不是多余
if(hash2[s[left] - 'a'] && hash1[s[left] - 'a'] <= hash2[s[left] - 'a'])
{
count1--;
}
hash1[s[left] - 'a']--;
left++;
}
//判断
//两个哈希表
if(right - left + 1 == p.length() && count1 == count2)
{
ret.push_back(left);
}
}
return ret;
}
};
7. 串联所有单词的子串
class Solution
{
public:
vector<int> findSubstring(string s, vector<string>& words)
{
vector<int> ret;
//right + words[0].length()边界问题
for (int i = 0; i < words[0].length(); i++)
{
map<string, int> m1;
map<string, int> m2;
for (auto e : words)
{
m1[e]++;
//cout << m1[e] << endl;
m2[e] = 0;
}
int count1 = 0;
int count2 = words.size();
//后续再遍历,少遍历一步
for (int right = i, left = i; right + words[0].length() - 1 < s.length(); right += words[0].length())
{
//进窗口
string part1(s.begin() + right, s.begin() + right + words[0].length());
//cout << part << endl;
//有效字符
if (m1[part1] > 0 && m2[part1] < m1[part1])
{
count1++;
}
m2[part1]++;
//cout << m2[part1] << endl;
//出窗口
int size = words.size() * words[0].length();
//cout << size << endl;
while (right + words[0].length() - left > size)
{
string part2(s.begin() + left, s.begin() + left + words[0].length());
//没有发生重复的有效字符
//只要是有效字符就--
if (m1[part2] > 0 && m2[part2] <= m1[part2])
{
count1--;
}
m2[part2]--;
left += words[0].length();
}
//判断
if (right + words[0].length() - left == words.size() * words[0].length() && count1 == count2)
{
count.push_back(left);
}
}
}
return ret;
}
};
8. 最小覆盖子串
class Solution {
public:
string minWindow(string s, string t)
{
//可以用数组代替map时,数组更优
int hash1[128] = {0};
int hash2[128] = {0};
//记录有效字符种类
int kind1 = 0;
for(auto e : t)
{
if(hash1[e]++ == 0)
{
kind1++;
}
//hash1[e]++;
}
//用有效字符种类的判断方式优于记录有效字符个数的判断方式
int kind2 = 0;
//记录子串长度
int len = INT_MAX;
//记录子串起始位置
int begin = -1;
for(int right = 0, left = 0; right < s.length(); right++)
{
//先进窗口再判断是否为有效字符
//hash2[s[right]]++;
if(hash1[s[right]] == ++hash2[s[right]])
{
kind2++;
}
//当遍历字符中包含有效字符时,进行判断,记录与出窗口操作
while(kind1 == kind2)
{
//判断
if(right - left + 1 < len)
{
begin = left;
len = right - left + 1;
}
//出窗口
//先判断再出窗口
if(hash1[s[left]] && hash1[s[left]] == hash2[s[left]])
{
kind2--;
}
hash2[s[left]]--;
left++;
}
}
//判断有无子串
if(begin == -1)
{
return "";
}
else
{
//取子串
return s.substr(begin, len);
}
}
};