每日算法刷题计划Day12 5.21:leetcode不定长滑动窗口求最短/最长3道题,,用时1h40min(有点长了)

求最短/最小

一般题目都有「至少」的要求。

窗口成立的条件,right右移增强条件,然后while循环left右移最终破坏条件

模版套路

在while循环内更新答案

复制代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n=nums.size();
        long long sum=0;
        int res=INT_MAX;
        int left=0;
        for(int right=0;right<n;++right){
	        // 1.入窗口
            sum+=nums[right];
            // 2.满足条件
            while(sum>=target){
	            // 2.1 更新答案
                res=min(res,right-left+1);
                // 2.2 出窗口
                sum-=nums[left];
                ++left;
            }
        }
        // 无答案
        if(res==INT_MAX)    return 0;
        return res;
    }
};
套路
题目描述

1.找出该数组中满足其总和大于等于 target (窗口条件)的长度最小 的 子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。如果不存在符合条件的子数组,返回 0

2.如果 s某个子字符串中 1 的个数恰好等于 k (窗口条件) ,则称这个子字符串是一个 美丽子字符串 。令 len 等于 最短 美丽子字符串的长度。返回长度等于 len 且字典序 最小 的美丽子字符串。如果 s 中不含美丽子字符串,则返回一个 字符串。(两重最小,长度最小+字典序最小)

3.假如在该字符串中,这四个字符都恰好出现 n/4 (题目条件,而不是窗口条件),那么它就是一个「平衡字符串」。给你一个这样的字符串 s,请通过「替换一个子串 」的方式,使原字符串 s 变成一个「平衡字符串」。你可以用和「待替换子串」长度相同的 任何 其他字符串来完成替换。请返回待替换子串的最小可能长度 。(题意转换,窗口内字符是可以替换的,即窗口内字符是任意分配的(不用具体在意是什么),能够让窗口外字符数量增加,但不会减少,所以一个窗口满足的条件就是窗口外4种字符的数量都小于等于n/4)

学习经验

1.与求最长/最大不同,最长/最大右移right会导致窗口不满足条件,所以while循环内是不满足条件就右移left直到满足条件 ,while循环结束窗口满足条件,更新答案。(while外更新答案)

而求最短/最小,右移right肯定更加满足条件 ,所以while循环内满足条件就先更新答案,然后右移left,直到不满足条件 ,然后right接着右移。(while内更新答案)

另一种思想是while中先假设右移left,若满足条件就进入while,然后真正右移left,while循环结束窗口肯定也满足条件,再判断满足条件(刚开始不一定满足)然后更新答案(while外更新答案)

1. 209.长度最小的子数组(中等,学习)

209. 长度最小的子数组 - 力扣(LeetCode)

思想

1.找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。如果不存在符合条件的子数组,返回 0

2.我的想法比较复杂,想跟求最长/最大套路一样,窗口不满足条件更新窗口,但是这题右移right会一直满足条件,所以想到左移left,但是得先找到第一个满足条件的窗口。所以先右移right找到第一个满足条件的区间[0,right),然后依次左移left,不满足条件就while右移right,使得区间[left+1,right)为窗口,但是因为right是开区间,会遇到无法再右移的情况,需要一个tag变量进行判断,并在res更新前判断tag退出for循环,调试了一会。

3.学习:

依旧是枚举右端点移动,简单直接

(1)在while循环结束后更新答案

  • 1.right入窗口
  • 2.假设 left左移,如果sum-nums[left]>=target,那么就while左移left
  • 3.满足条件(判断一开始不满足条件的情况,能左移说明左移完肯定满足条件)则更新res
    (2)在while循环内更新答案(学习)
  • 1.right入窗口
  • 2.满足要求进入while循环,先更新答案,后左移left
代码

c++ :

1.我的

复制代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        long long sum = 0;
        int right = 0;
        while (right < n && sum < target) {
            sum += nums[right];
            ++right;
        }
        if (sum < target)
            return 0;
        int res = right;
        bool tag = false;
        // 区间:[left+1,right)
        for (int left = 0; left < n; ++left) {
            sum -= nums[left];
            while (sum < target) {
                if (right == n) {
                    tag = true;
                    break;
                }
                sum += nums[right];
                ++right;
            }
            if (tag)
                break;
            res = min(res, right - left - 1);
        }
        return res;
    }
};

2.在while循环外更新答案

复制代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        long long sum = 0;
        int left = 0;
        int res = INT_MAX;
        for (int right = 0; right < n; ++right) {
            sum += nums[right];
            while (sum - nums[left] >= target) {
                sum -= nums[left];
                ++left;
            }
            if (sum >= target)
                res = min(res, right - left + 1);
        }
        if (res == INT_MAX)
            return 0;
        return res;
    }
};

3.在while循环内更新答案

复制代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n=nums.size();
        long long sum=0;
        int res=INT_MAX;
        int left=0;
        for(int right=0;right<n;++right){
            sum+=nums[right];
            while(sum>=target){
                res=min(res,right-left+1);
                sum-=nums[left];
                ++left;
            }
        }
        if(res==INT_MAX)    return 0;
        return res;
    }
};
2. 2904.最短且字典序最小的美丽子字符串(中等)

2904. 最短且字典序最小的美丽子字符串 - 力扣(LeetCode)

思想

1.如果 s某个子字符串中 1 的个数恰好等于 k (窗口条件) ,则称这个子字符串是一个 美丽子字符串 。令 len 等于 最短 美丽子字符串的长度。返回长度等于 len 且字典序 最小 的美丽子字符串。如果 s 中不含美丽子字符串,则返回一个 字符串。

2.这题要求答案字符串长度最短且字典序最小,两重最小

3.字符串初始设置最大值string strmax(n+1,'z')

4.字符串重要的substr(pos,len)函数

代码

c++:

复制代码
class Solution {
public:
    string shortestBeautifulSubstring(string s, int k) {
        int n = s.size();
        long long sum1 = 0;
        string strmax(n + 1, 'z'); // 初值最大值,等价于INT_MAX
        string res = strmax;
        int left = 0;
        for (int right = 0; right < n; ++right) {
            if (s[right] == '1')
                ++sum1;
            while (sum1 == k) {
                string t = s.substr(left, right - left + 1);
                if (t.size() < res.size()) {
                    res = t;
                } else if (t.size() == res.size()) {
                    res = min(res, t);
                }
                if (s[left] == '1')
                    --sum1;
                ++left;
            }
        }
        if (res == strmax)
            return "";
        return res;
    }
};
3. 1234.替换子串得到平衡字符串(中等,学习思想)

1234. 替换子串得到平衡字符串 - 力扣(LeetCode)

思想

1.假如在该字符串中,这四个字符都恰好出现 n/4 次,那么它就是一个「平衡字符串」。给你一个这样的字符串 s,请通过「替换一个子串 」的方式,使原字符串 s 变成一个「平衡字符串」。你可以用和「待替换子串」长度相同的 任何 其他字符串来完成替换。请返回待替换子串的最小可能长度

2.题意转换,窗口内字符是可以替换的,即窗口内字符是任意分配的(不用具体在意是什么),能够让窗口外字符数量增加,但不会减少,所以一个窗口满足的条件就是窗口外4种字符的数量都小于等于n/4, 从而窗口内的字符能分配使总字符都为n/4

所以需要维护每种字符窗口外的数量,利用map

代码

c++:

复制代码
class Solution {
public:
    int balancedString(string s) {
        int n = s.size();
        int avg = n / 4;
        unordered_map<char, int> cnt;
        for (char c : s)
            ++cnt[c];
        if (cnt['Q'] == avg && cnt['W'] == avg && cnt['E'] == avg &&
            cnt['R'] == avg)
            return 0;
        int res = INT_MAX;
        int left = 0;
        for (int right = 0; right < n; ++right) {
            // 入窗口相当于窗口外字符数量减少
            --cnt[s[right]];
            while (cnt['Q'] <= avg && cnt['W'] <= avg && cnt['E'] <= avg &&
                   cnt['R'] <= avg) {
                res = min(res, right - left + 1);
                // 出窗口相当于窗口外字符数量增加
                ++cnt[s[left++]];
            }
        }
        return res;
    }
};
相关推荐
68岁扶墙肾透5 分钟前
Java安全-Servlet内存马
java·安全·web安全·网络安全·系统安全·网络攻击模型
码农爱java7 分钟前
Elasticsearch 深入分析三种分页查询【Elasticsearch 深度分页】
java·大数据·spring boot·后端·elasticsearch·全文检索
_extraordinary_1 小时前
Java 继承
java·开发语言·继承
小鹭同学_1 小时前
Java基础 Day17
java·开发语言
fouen1 小时前
贪心算法理论篇
数据结构·python·算法·贪心算法
设计师小聂!1 小时前
Spring ---IOC容器和DI的具体应用
java·后端·spring
徐子宸2 小时前
docker面试题(4)
java·spring cloud·docker
潇凝子潇2 小时前
IntelliJ IDEA设置编码集
java·ide·intellij-idea
❀͜͡傀儡师2 小时前
IntelliJ IDEA 接入 DeepSeek帮助你更好编码
java·ide·intellij-idea
我命由我123452 小时前
IDEA - Windows IDEA 代码块展开与折叠(基础折叠操作、高级折叠操作)
java·笔记·后端·java-ee·intellij-idea·学习方法·intellij idea