文章目录
- Leetcode1658. 将 x 减到 0 的最小操作数
- 题目
- 解法(滑动窗口)
- Leetcode904. 水果成篮
- 题目
- 解法(滑动窗口)
- Leetcode438. 找到字符串中所有字母异位词
- 题目
- 解法(滑动窗口)
Leetcode1658. 将 x 减到 0 的最小操作数
题目
Leetcode1658. 将 x 减到 0 的最小操作数
解法(滑动窗口)
题目的意思就是左边或者右边减掉一个数,使减掉的数的和恰好为 x ,我们其实并不能很清楚的知道应该从哪边开始减,这样问题就变得复杂起来。因此,我们对题目进行一个转化,等价为
求数组内一段连续的、最长的和为sum(nums) - x的数组
- 首先转换问题,
int target = sum(nums) - x
。特判一下如果target < 0
,则无解,这也就意味着我把你数组内的所有元素都减完,我x
仍然大于0;- 初始化左右指针
int left = 0, right = 0
- 当
right < nums.size()
时,一直循环;
进窗口
if(t > target)
, 出窗口
代码
class Solution
{
public:
int minOperations(vector<int>& nums, int x)
{
int sum = 0;
for(auto e:nums) sum += e;//求整个数组的和
int res = -1;
int target = sum - x; //转换问题
if(target < 0) return -1;//特判
for(int left = 0, right = 0, t = 0; right < nums.size(); right++)
{
t += nums[right];//进窗口
while(t > target)//判断
t -= nums[left++];//出窗口
if(t == target) res = max(res, right - left + 1);//更新结构
}
return res == -1 ? -1 : nums.size() - res;
}
};
Leetcode904. 水果成篮
题目
Leetcode904. 水果成篮
解法(滑动窗口)
使窗口内的水果种类只有两种
右端⽔果进⼊窗⼝的时候,⽤哈希表统计这个⽔果出现的次数。这个⽔果进来后,判断哈希表的大小:
如果大于2,说明窗口中水果种类超过两种。那么左侧窗口就依次出水果并更新哈希表内水果种类,直至哈希表大小等于2,那么更新结果;
如果小于等于2,那么直接更新结果;
//使用容器
class Solution
{
public:
int totalFruit(vector<int>& fruits)
{
unordered_map<int, int> hash; // 统计窗⼝水果的种类
int res = 0;
for(int left = 0, right = 0; right < fruits.size(); right++)
{
int in = fruits[right];
hash[in]++;//进窗口
while(hash.size() > 2)//判断
{
int out = fruits[left];
hash[out]--;//出窗口
//当左侧水果种类个数为零的时候,从hash中剔除
if(hash[out] == 0) hash.erase(out);
left++;
}
res = max(res, right - left + 1);
}
return res;
}
};
但是使用容器的话,需要不停地在hash中插入数据,这样消耗其实是非常大的,下面我们使用数组模拟hash,这样消耗就会小一点,
//⽤数组模拟哈希表
class Solution
{
public:
int totalFruit(vector<int>& fruits)
{
int hash[100001] = {0};//数组模拟哈希表
int res = 0;
int kinds = 0;//记录水果的种类
for(int left = 0, right = 0; right < fruits.size(); right++)
{
int in = fruits[right];
if(hash[in]++ == 0) kinds++;//维护kinds水果种类以及进窗口
while(kinds > 2)//判断
{
int out = fruits[left];
if(--hash[out] == 0) kinds--;//维护kinds水果种类以及出窗口
left++;
}
res = max(res, right - left + 1);//更新结果
}
return res;
}
};
Leetcode438. 找到字符串中所有字母异位词
题目
Leetcode438. 找到字符串中所有字母异位词
解法(滑动窗口)
- 因为字符串 p 的异位词的⻓度⼀定与字符串 p 的⻓度相同,所以我们可以在字符串 s 中构造⼀个⻓度为与字符串 p 的⻓度相同的滑动窗⼝,维护窗口中没中字母出现的次数;
- 当窗⼝中每种字⺟的数量与字符串 p 中每种字⺟的数量相同时,则说明当前窗⼝为字符串 p 的异位词;
- 我们使用两个数组来模拟哈希表,⼀个来保存 s 中的⼦串每个字符出现的个数,另⼀个来保存 p 中每⼀个字符出现的个数。
当我们更新结果时,可以对其进行如下优化
进窗口后,if(hash2[in - 'a'] <= hash1[in - 'a']) count++;
出窗口前,if(hash2[out - 'a'] <= hash1[out - 'a']) count--;
当count == p.size()时,更新结果
class Solution
{
public:
vector<int> findAnagrams(string s, string p)
{
int hash1[26] = {0};//统计p中每个字母出现的个数
for(auto e:p) hash1[e - 'a']++;
vector<int> res;
int hash2[26] = {0};//统计窗口中每个字符的个数
for(int left = 0, right = 0, count = 0; right < s.size(); right++)
{
char in = s[right];
hash2[in - 'a']++;//进窗口
if(hash2[in - 'a'] <= hash1[in - 'a']) count++;//维护count;
if(right - left + 1 > p.size())//判断
{
char out = s[left++];
if(hash2[out - 'a'] <= hash1[out - 'a']) count--;//维护count;
hash2[out - 'a']--;//出窗口
}
if(count == p.size()) res.push_back(left);
}
return res;
}
};