
今日语录:人生就是这样,要耐的住寂寞,才守得住繁华
文章目录
- 🚀一、长度最小的子数组
- 🎉二、无重复字符的最长子串
- [🚘三、最大连续1的个数 III](#🚘三、最大连续1的个数 III)
- 🎡四、将x减到0的最小操作数
- 🏝️五、找到字符中所有字母的异位词
- ⭐六、串联所有单词的子串
🚀一、长度最小的子数组
题目链接:长度最小的子数组
题目描述:
解题思路:
1.暴力枚举,枚举任意一个数字当作起始位置,然后从这个位置开始寻找一段最短区间满足 >= target(注:这方法会超时,效率低)
2.滑动窗口 ,由于题目要的是一段连续的区间,因此我们可以采用滑动窗口的办法。使用两个指针left和right同时指向起始位置,在right小于数组长度前提下,不断向右移动进行累加操作(进窗口 )直到它 >= target(判断条件 ),记录该段区间的长度(更新结果 ),然后将左端元素划出去(出窗口)同时并判断是否满足条件,如果不满足,则让right++ (进入下一个窗口)
代码实现:
cpp
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int ret = INT_MAX,sum = 0;
for(int left = 0,right = 0;right < nums.size();right++)
{
sum += nums[right];
while(sum >= target)
{
//更新结果
ret = min(ret,right - left + 1);
sum -= nums[left++];
}
}
return ret == INT_MAX ? 0 : ret;
}
};
🎉二、无重复字符的最长子串
题目链接:无重复字符的最长子串
题目描述:
解题思路:
1.暴力枚举,从每一个位置开始向后,看看无重复字符在什么位置,返回长度最长的那个(注:效率低)
2.滑动窗口 + 哈希表 ,题目要求依旧是一段连续的区间,因此可以采用滑动窗口的办法。定义两个指针left 和 right,让右端元素right进入窗口(进窗口 ),并用哈希表统计该字符的频次,如果该字符 > 1(判断条件 ),则从左侧开始滑出窗口(出窗口 ),直到该字符的频次为1时,更新结果
代码实现:
cpp
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int hash[128] = {0};
int n = s.size();
int ret = 0;
for(int left = 0,right = 0;right < n;right++)
{
hash[s[right]]++;
while(hash[s[right]] > 1)
{
hash[s[left++]]--;
}
ret = max(ret,right - left + 1);
}
return ret;
}
};
🚘三、最大连续1的个数 III
题目链接:最大连续1的个数 III
题目描述:
解题思路:
1.因为该题的要求依旧是一段连续的空间,因此我们可以采用滑动窗口的方法来解决。
2.我们不要想着如何去翻转,把问题复杂化。它的核心就是0的个数不超过k个,我们只要解决这一问题即可
3.可以使用一个变量zero来记录0的个数,用两个指针left和right,right指针负责进窗口 ,当遇到0时让zero++,直到当zero > k时(判断条件 ),判断left所指元素是否为0进行出窗口 ,最后更新结果
代码实现:
cpp
class Solution {
public:
int longestOnes(vector<int>& nums, int k) {
int n = nums.size();
int len = 0;
for(int left = 0,right= 0,zero = 0;right < n;right++)
{
if(nums[right] == 0)
{
zero++;
}
while(zero > k)
{
if(nums[left++] == 0)
{
zero--;
}
}
len = max(len,right - left + 1);
}
return len;
}
};
🎡四、将x减到0的最小操作数
题目链接:将x减到0的最小操作数
题目描述:
解题思路:
由于题目要求的是减去数组左或右两端连续的和为x的最短数组,如果按照题目的要求那我们解决这个问题就比较棘手,由于我们不知道它是减去左边的还是减去右边的,或者连续减去左边等情况,因此我们可以将其进行转化为数组内一段连续的和为sum(nums) - x的最长数组,使用滑动窗口的解法,然后用整个数组的大小减去该段最长数组的大小,我们就得到了题目要求的最短操作数了
代码实现:
cpp
class Solution {
public:
int minOperations(vector<int>& nums, int x) {
int sum = 0;
for(auto n : nums)
{
sum += n;
}
int ret = -1;
int target = sum - x;
if(target < 0)
{
return -1;
}
for(int left = 0,right = 0,tmp = 0;right < nums.size();right++)
{
tmp += nums[right];
while(tmp > target)
{
tmp -= nums[left++];
}
if(tmp == target)
{
ret = max(ret,right - left + 1);
}
}
if(ret == -1)
return ret;
else
return nums.size() - ret;
}
};
🏝️五、找到字符中所有字母的异位词
题目链接:找到字符中所有字母的异位词
题目描述:
解题思路:
滑动窗口+ 哈希表 ,由题可知,字符串p的异位词的长度⼀定与字符串p的长度相同,所以可以在字符串s 中构造⼀个长度为字符串p的长度相同的滑动窗口,用哈希表记录字符串p中字符出现的个数,用一个变量count记录长度,不断进窗口 ,如果大于异位词的长度并且出现的字符在字符串p中也有(判断条件 ),就出窗口 ,让count--,相反就让count++,如果等于字符串p的长度就更新结果
代码实现:
cpp
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> ret;
int hash1[26] = {0};
int n = s.size();
int m = p.size();
for(auto ch : p)
{
hash1[ch - 'a']++;
}
int hash2[26] = {0};
int count = 0;
for(int left = 0,right = 0;right < n;right++)
{
char in = s[right];
if(++hash2[in - 'a'] <= hash1[in - 'a'])
{
count++;
}
if(right - left + 1 > m)
{ char out = s[left++];
if(hash2[out - 'a']-- <= hash1[out - 'a'])
{
count--;
}
}
if(count == m)
{
ret.push_back(left);
}
}
return ret;
}
};
⭐六、串联所有单词的子串
题目链接:串联所有单词的子串
题目描述:
解题思路:
这道题的解法与上道题的异位词解法类似,无非就是把字母转化为一个单词,因此同样采用哈希 + 滑动窗口的解法
代码实现:
cpp
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> ret;
unordered_map<string ,int> hash1;
for(auto& e:words)
{
hash1[e]++;
}
int len = words[0].size();
int m = words.size();
for(int i = 0;i < len;i++)
{
unordered_map<string,int> hash2;
for(int left = i,right = i,count = 0;right + len <= s.size();right += len)
{
string in = s.substr(right,len);
hash2[in]++;
if(hash2[in] <= hash1[in])
{
count++;
}
if(right - left + 1 > len * m)
{
string out = s.substr(left,len);
if(hash2[out] <= hash1[out])
{
count--;
}
hash2[out]--;
left += len;
}
if(count == m)
{
ret.push_back(left);
}
}
}
return ret;