Skip to content

不定长滑动窗口

3. 无重复字符的最长子串 未解决

题意

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

思路

  • 需要熟练运用map,重复想到set或map,连续子串想到窗口
  • 要注意这些:
    • 一是连续性,abca,滑动到第二个a,删除最左边的就行
    • 二是注意这个while可以让指针连续移动,直到重复字符那里
    • 三是复杂度O(n),虽然嵌套了 while,但每个字符最多被 left 和 right 各访问一次

代码

cpp
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n = s.length(), ans = 0, left = 0;
        unordered_map<char, int> cnt; // 维护从下标 left 到下标 right 的字符
        for (int right = 0; right < n; right++) {
            char c = s[right];
            cnt[c]++;
            while (cnt[c] > 1) { // 窗口内有重复字母
            //注意,这里不是用count,直接用value就行了
                cnt[s[left]]--; // 移除窗口左端点字母
                left++; // 缩小窗口
            }
            ans = max(ans, right - left + 1); // 更新窗口长度最大值
        }
        return ans;
    }
};

1493. 删掉一个元素以后全为1的最长子数组 已解决

题意

给你一个二进制数组 nums ,你需要从中删掉一个元素。 请你在删掉元素的结果数组中,返回最长的且只包含 1 的非空子数组的长度。 如果不存在这样的子数组,请返回 0 。

思路

最长的子数组 - 不定长滑动窗口 用样例模拟了一下,发现: 删掉一个元素 - map中的 0 键对应的值 只能为1

那么问题转化为: 只含一个0的最长滑动窗口长度减去1,,,做的时候发现答案也可以是value(1)

代码

cpp
class Solution {
public:
    int longestSubarray(vector<int>& nums) {
        //不定长滑动窗口,问题可以转化为,只含1个0的最长滑动窗口的值减去1
        //int,int型的map,
        int l = 0, ans  = 0;
        unordered_map<int,int> mp;
        for(int i = 0; i < nums.size(); i++){
            mp[nums[i]]++;

            while(mp[0] > 1){
                mp[nums[l]]--;
                l++;
            }
            
            ans = max(ans,mp[1]);
        }
        return mp[0] == 0 ? ans - 1 : ans;

    }
};

3411. 使数组平衡的最少移除数目 已解决

题意

给你一个整数数组 nums 和一个整数 k。 如果一个数组的 最大 元素的值 至多 是其 最小 元素的 k 倍,则该数组被称为是 平衡 的。 你可以从 nums 中移除 任意 数量的元素,但不能使其变为 空 数组。

返回为了使剩余数组平衡,需要移除的元素的 最小 数量。

注意:大小为 1 的数组被认为是平衡的,因为其最大值和最小值相等,且条件总是成立。

思路

子数组,这个窗口是不断减小的可以先排序吧,排序之后,样例通过 好吧,错误,没有考虑到可以移除最小值 好吧,解答错误,其实也可以移除左边再右边,那么思路应该是 逆向思路,排好序,求符合条件的最长子数组,一旦不符合条件,左指针右移动,更新答案, 返回长度减去最长的子数组长度

代码

cpp
class Solution {
public:
    int minRemoval(vector<int>& nums, int k) {
        //子数组,这个窗口是不断减小的可以先排序吧,排序之后,样例通过
        //好吧,错误,没有考虑到可以移除最小值
        //好吧,解答错误,其实也可以移除左边再右边,那么思路应该是
        //逆向思路,排好序,求符合条件的最长子数组,一旦不符合条件,左指针右移动,更新答案,
        //返回长度减去最长的子数组长度
        sort(nums.begin(),nums.end());
        int n = nums.size(),l = 0,res = 0;

        for(int i = 0; i < n; i++){
            while(nums[i] > nums[l]*(long long)k){
                l++;
            }
            res = max(res,i - l + 1);
        }
        return n - res;
    }
};

1208. 尽可能使字符串相等 未解决

题意

给两个长度相同的字符串,s 和 t。

将 s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销(开销可能为 0),也就是两个字符的 ASCII 码值的差的绝对值。

用于变更字符串的最大预算是 maxCost。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。

如果你可以将 s 的子字符串转化为它在 t 中对应的子字符串,则返回可以转化的最大长度。

如果 s 中没有子字符串可以转化成 t 中对应的子字符串,则返回 0。

思路

...

代码

cpp
// 代码

904. 水果成篮 已解决

题意

你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。

你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:

  • 你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
  • 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
  • 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。

给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。

思路

两个篮子,试试用map的size函数吧, 进入map,当size>=3 左边删,左边出 ans = max.... 不定长

代码

cpp
class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        //两个篮子,试试用map的size函数吧,
        //进入map,当size>=3 左边删,左边出
        //ans = max....
        //不定长
        int l = 0, ans = 0;
        unordered_map<int,int> mp;
        for(int i = 0; i < fruits.size(); i++){
            mp[fruits[i]]++;
            while(mp.size() > 2){
                mp[fruits[l]]--;
                if(mp[fruits[l]] == 0) mp.erase(fruits[l]);
                l++;
            }
            ans = max(ans, i - l + 1);

        }
        return ans;
    }
};