【算法深练】分组循环:“分”出条理,化繁为简 - 教程

news/2025/10/6 12:14:41/文章来源:https://www.cnblogs.com/ljbguanli/p/19127471

【算法深练】分组循环:“分”出条理,化繁为简 - 教程

目录

引言

分组循环

2760. 最长奇偶子数组

1446. 连续字符

1869. 哪种连续子字符串更长

2414. 最长的字母序连续子字符串的长度

3456. 找出长度为 K 的特殊子字符串

1957. 删除字符使字符串变好

674. 最长连续递增序列

978. 最长湍流子数组

2110. 股票平滑下跌阶段的数目

228. 汇总区间

1887. 使数组元素相等的减少操作次数

845. 数组中的最长山脉

2038. 如果相邻两个颜色均相同则删除当前颜色

2900. 最长相邻不相等子序列 I

3011. 判断一个数组是否可以变为有序

1578. 使绳子变成彩色的最短时间

1759. 统计同质子字符串的数目

1839. 所有元音按顺序排布的最长子字符串

2765. 最长交替子数组

3255. 长度为 K 的子数组的能量值 II

3350. 检测相邻递增子数组 II

3105. 最长的严格递增或递减子数组

拓展 (加餐)

838. 推多米诺

467. 环绕字符串中唯一的子字符串

3499. 操作后最大活跃区段数 I

2593. 标记所有元素后数组的分数

2948. 交换得到字典序最小的数组

总结


引言

分组循环可以归为同向双指针这一类题目,不同的是将双指针优化为单指针并记录每组的起始位置。

适用场景:按照题目要求,数组会被分割成若干组,每一组的判断/处理逻辑是相同的。

核心思想

  • 外层循环负责遍历组之前的准备工作(记录开始位置),和遍历组之后的统计工作(更新答案最大值)。
  • 内层循环负责遍历组,找出这一组最远在哪结束。

PS:本篇博客中的所有题目均来自于灵茶山艾府 - 力扣(LeetCode)分享的题单。 

分组循环

2760. 最长奇偶子数组

 题解:此题不再是只有一个起点,而是多起点;找出满足题意的最长子数组;外层循环即可起始位置,内层循环找该子数组满足题意的最长位置。

class Solution {public:    int longestAlternatingSubarray(vector& nums, int threshold) {        //找到最长数组,数组满足两个条件:1)奇偶交替;2)子数组最大值不超过threhold        int i=0,n=nums.size();        int ret=0;        while(ithreshold)) i++;   //先找到满足题意的第一个位置            int start=i;   //记录起始位置            while((i

1446. 连续字符

题解:经典的分组循环题目,从多个字符起点开始,找出最长的相同子字符串的长度。

class Solution {public:    int maxPower(string s) {        int n=s.size();        int i=0,ret=0;        while(i

1869. 哪种连续子字符串更长

题解:与上一题一样,但是此题有两种字符需要进行记录;因此可以直接使用两个整形对两种字符的最长长度进行记录即可。

class Solution {public:    bool checkZeroOnes(string s) {        //分别记录1和0的最长字符串的长度        int n=s.size();        int i=0;        int one=0,zero=0;        while(izero;    }};

2414. 最长的字母序连续子字符串的长度

题解:分组循环,只是子数组判断条件不同,要求字母序连续。

class Solution {public:    int longestContinuousSubstring(string s) {        //字母序连续        int n=s.size();        int i=0,ret=0;        while(i

3456. 找出长度为 K 的特殊子字符串

题解:不需要控制长为K区间来判断时候满足条件,可以直接找出每一段字符串中相同字符的个数,判断该长度是否是K即可。

class Solution {public:    bool hasSpecialSubstring(string s, int k) {        //找长度为K的相同字符串的长度        int n=s.size();        int i=0;        while(i

1957. 删除字符使字符串变好

题解:连续字符的个数不超过3,可以在内循环中判断以下该重复字符是第几个,能否进行插入。

class Solution {public:    string makeFancyString(string s) {        int n=s.size();        int i=0;        string ret;        while(i

674. 最长连续递增序列

题解:找出最长的子数组,遍历数组;通过外层循环记录起始位置,内层循环找出子数组结束的位置。

class Solution {public:    int findLengthOfLCIS(vector& nums) {        //找递增的子数组        int n=nums.size();        int i=0,ret=0;        while(inums[i-1])) i++;  //判断是否是递增子数组             ret=max(ret,i-start);  //更新答案        }        return ret;    }};

978. 最长湍流子数组

题解:湍流数组,递增和递减是交替进行的。外层循环进行记录起始位置和过滤相同位置,内层循环找出子数组的最长长度。细节:用flag记录i位置前面的增长趋势,使用flag*(nums[i+1]-nums[i])<0时注意乘法可能会导致越界。

class Solution {public:    int maxTurbulenceSize(vector& arr) {        //数组一增一减的趋势        int n=arr.size();        if(n==1) return 1;        int i=0,ret=1;        while(i0?1:-1;  //记录上一个位置是递增还是递减            while(i0?1:-1;    //更新flag记录的位置                i++;            }             ret=max(ret,i-start+1);  //更新答案        }        return ret;    }};

2110. 股票平滑下跌阶段的数目

题解:外层循环记录起始位置,内层循环找从该位置开始最长的平缓数组长度K,根据子数组的长度再求出其子数组的个数:K(K+1)/2;

class Solution {public:    long long getDescentPeriods(vector& prices) {        //一段平滑下跌子数组的长度为k        //其满足条件的子数组个数为:k+k-1+k-2+k-3....+1为(k+1)*k/2         int n=prices.size();        long long i=0,ret=0;        while(i

228. 汇总区间

题解:与上一题类似,找连续递增的子数组,并且每次递增1。

class Solution {public:    vector summaryRanges(vector& nums) {        //进行分组循环        int n=nums.size();        int i=0;        vector ret;        while(i";                tmp+=to_string(nums[i]);                ret.push_back(tmp);            }            i++;        }        return ret;    }};

1887. 使数组元素相等的减少操作次数

题解:进行模拟;先对数组进行排序,从后往前遍历,当前位置与前一个位置不同时要对[i,n-1]进行改变;向前遍历直到遍历到0停止。

class Solution {public:    int reductionOperations(vector& nums) {        //先对数组进行排序        int n=nums.size();        sort(nums.begin(),nums.end());        //从n-1开始往前找        int i=n-1,ret=0;        while(i>0)        {            if(nums[i-1]!=nums[i]) ret+=n-i;            i--;        }        return ret;    }};

845. 数组中的最长山脉

题解:使用分组循环,外循环记录起始位置,内循环用两个来分别记录左侧山脉长度和右侧山脉长度。

class Solution {public:    int longestMountain(vector& arr) {        //分别求单调递增和递减区间        int ret=0,n=arr.size();        int i=0;        while(iarr[i+1])  //记录山脉右侧            {                flag2=1;                i++;            }            if(flag1&&flag2)            ret=max(ret,i-start+1);            if(i

2038. 如果相邻两个颜色均相同则删除当前颜色

题解:通过相同子字符串的长度就可以判断出一个玩家对于该子字符串可以进行多少次删除操作,比如AAAAA,Alice可以进行3次删除操作;因此通过分组循环分别记录两个玩家可以进行删除操作的次数就可以确定玩家。

class Solution {public:    bool winnerOfGame(string colors) {        //通过记录重复字符的个数来判断每个人能够进行多少次删除操作        int dela=0,delb=0;        int n=colors.size();        int i=0;        while(i=3&&colors[start]=='A') dela+=i-start-2;   //判断A和B可以删除的次数            else if(i-start>=3&&colors[start]=='B') delb+=i-start-2;         }        return dela>delb;    }};

2900. 最长相邻不相等子序列 I

题解:注意题目中:“不能出现连续的0或1”,不能出现连续的0或1,则对于连续的0或1,我们只取其中一个添加到答案中即可;使用分组循环找出连续的0或1。

class Solution {public:    vector getLongestSubsequence(vector& words, vector& groups) {        int n=words.size();        int i=0;        vector ret;  //记录结果        while(i

3011. 判断一个数组是否可以变为有序

题解:使用分组循环将数组依据二进制中1的个数进行分配,将每一组的元素大小与上一组中最大值进行比较,判断是否可以进行排序。关于二进制中1的计算可以使用内置函数

__builtin_popcount(int n)
class Solution {    //计算二进制位中1的个数    int setbit(int n)    {        int count = 0;        while (n)        {            n = n & (n - 1);            count++;        }        return count;    } public:    bool canSortArray(vector&  nums) {        int pre_max = 0;  //记录上一个最小值        int n = nums.size(), i = 0;        while (i < n )        {            int start = setbit(nums[i]);  //记录开始位置的二进制位个数            int in_max = 0;            while (i < n && setbit(nums[i]) == start)            {                if(nums[i]

1578. 使绳子变成彩色的最短时间

题解:分组循环,将相同颜色的气球作为一组,将相同颜色的气球进行删除,删除时为了花费最小的时间,将花费时间长的进行保留。

class Solution {public:    int minCost(string colors, vector& neededTime) {        //将有多余颜色的气球删除,保留连续颜色中移除时间最小的一个        int n=colors.size();        int i=0,ret=0;        while(i1) ret+=sum-in_max;        }        return ret;    }};

1759. 统计同质子字符串的数目

题解:计算每一组相同字符串的长度K,每一组会使得结果增加k+k-1+k-2+k-3...+2+1 即(k+1)*k/2。

class Solution {    #define MOD 1000000007 public:    int countHomogenous(string s) {        //计算每一组相同字符串的长度K,每一组会使得结果增加k+k-1+k-2+k-3...+2+1 即(k+1)*k/2                int n=s.size();        int i=0;        long long ret=0;        while(i

1839. 所有元音按顺序排布的最长子字符串

题解:分组循环,以每一个a开头的字符串作为一组,记录该字符串长度并判断是否由所有元音字母按顺序组成的。

class Solution {public:    int longestBeautifulSubstring(string word) {        vector vowel({'a','e','i','o','u'});         int n=word.size();        int i=0,ret=0;        while(i

2765. 最长交替子数组

题解:根据s[m - 1] - s[m - 2] = (-1)^m可以推出nums[ i - 1]==nums[ i + 1];一次对数组进行分组以s1=s0+1的位置为起始位置,进行循环找到最长子数组。

class Solution {public:    int alternatingSubarray(vector& nums) {        int i=0,n=nums.size();        int ret=-1;        while(i

3255. 长度为 K 的子数组的能量值 II

题解:分组循环,将每一个递增为1的子数组作为一组,当该子数组的长度>=k的时候就有能量值,继续向后查找看子数组是否还能更长,如果能则nums[i]就是下一组的能量值。对于输出数组可以与原数组之间建立位置关系,i----->i-k+1的位置,这样就可以依据i位置确定答案更新到的具体下标位置。

class Solution {public:    vector resultsArray(vector& nums, int k) {        //使用分组循环,将连续递增的数据分为一组,当该组的长度>=k的时候就可以将最大元素放入即nums[i]        //根据放入元素下标可以与返回结果下标建立联系,nums[i]放在i-k+1的位置                if(k==1) return nums;  //对于k==1就不需要找子数组,直接进行返回即可        int n=nums.size();        vector ret(n-k+1,-1);   //将数组初始化为-1        int i=0;        while(i=k) ret[i-k+1]=nums[i];  //当子数组长度大于等于k时就可以进行插入                i++;            }        }        return ret;    }};

3350. 检测相邻递增子数组 II

题解:根据题意,找两个长度相同相邻且都是严格递增的数组;使用分组循环,计算出一个长度为len的连续递增子数组后,1)可以与上一个相邻子数组进行组合,找到合适的k,k就是两个连续数组长度的较小的哪一个;2)还可以将长度为len的数组拆分为两个长度为len/2的数组,也是满足条件的。

class Solution {public:    int maxIncreasingSubarrays(vector& nums) {        //分组循环,对每次查找的递增数组进行记录        int n=nums.size();        int i=0;        int prev=0,k=0;        while(i

3105. 最长的严格递增或递减子数组

题解:找严格递增和严格递减的数组,使用分组循环,将每一个严格递增或递减的数组分为一组。

class Solution {public:    int longestMonotonicSubarray(vector& nums) {        //简单的分组循环        int n=nums.size();        int i=0,ret=1;        while(inums[i+1]) i++;            while(flag>0&&i

拓展 (加餐)

838. 推多米诺

题解:可能会出现的情况有4种:1)[L,L],[R,R]这两种都是可以直接对数组进行修改的;2)[L,R]是不需要进行操作的;3)[R,L]是需要对中间进行操作的。

如果数组最前面一个非.字符是L的话,为了组成[L,L]的形式,在原数组前面插上一个哨兵为L,结尾一样插入一个R

class Solution {public:    string pushDominoes(string dominoes) {        //将区间可以分为始终[L,L],[R,R]这两种都是可以直接对数组进行修改的        //[L,R]是不需要进行操作的;        //[R,L]是需要对中间进行操作的         // 如果数组最前面一个非.字符是L的话,为了组成[L,L]的形式,在原数组前面插上一个哨兵为L,结尾一样插入一个R        string s="L"+dominoes+"R";        int n=s.size();        int prev=0;  //记录上一个字符位置        for(int i=1;i

467. 环绕字符串中唯一的子字符串

题解:因为不能有重复的子字符串所以要进行筛选,如果直接存储每个已经存在的子字符串效率太低;此处可以使用一个哈希表来存储以每一个字符为结尾的子字符串的个数;

以当前字符为结尾,使得循环可以一直向后走也能保证记录每一个子字符串。

class Solution {public:    int findSubstringInWraproundString(string s) {        //环绕字符串种唯一的子字符串        //因为不能有重复的子字符串所以要进行筛选        //如果直接存储每个已经存在的子字符串效率太低                //可以使用一个哈希表来存储每一个以当前字符结尾的子字符串的个数        //以当前字符为结尾,使得循环可以一直向后走也能记录每一个子字符串         int n=s.size();        int i=0,ret=0;        int l=0;        vector length(26,0);  //记录以每一个字符为结尾字符串的长度        for(int i=0;i0&&(s[i-1]-'a'+1)%26!=s[i]-'a') l=i;  //如果不是环绕字符串重新开始             int len=i-l+1;    //计算前面环绕字符串的长度            if(len>length[s[i]-'a'])   //如果以当前字符结尾的字符串长度比之前数组种记录的更长就需要对结果进行更新            {                ret+=len-length[s[i]-'a'];                length[s[i]-'a']=len;            }        }        return ret;    }};

3499. 操作后最大活跃区段数 I

题解:根据题意就是找  0----1----0区段中1旁边两个0个数之和最大值,将这些0变成1后活跃区段就是最大值。可以先将所有的0区段的长度进行存储,再找出相邻区段和的最大值。

class Solution {public:    int maxActiveSectionsAfterTrade(string s) {        //找0  ---- 1 ---- 0的区间,将每一个0区间段的个数进行记录,然后找到两个相邻区段最大和        int n=s.size();        int i=0,ret=0;        vector zero;   //记录每一个区间中0的个数        while(imore) more=tmp;            tmp-=zero[l++];        }        return ret+more;    }};

可以对上面代码进行优化,不进行0的个数存储,只记录两个0区段之和的最大值。

class Solution {public:    int maxActiveSectionsAfterTrade(string s) {        //进行优化        int n=s.size(),i=0;        int ret=0;        int prev=INT_MIN,zero=0;   //用prev记录上一个0区段的长度,zero记录相邻两个0区段和的最大值        while(i

2593. 标记所有元素后数组的分数

题解:对数组下标和元素大小进行排序,从小到大依次进行选择,将被选择的元素左右下标元素进行删除即可。

class Solution {public:    long long findScore(vector& nums) {        //带下标进行排序        int n=nums.size();        vector> tmp;        for(int i=0;i x,pair y){            if(x.first!=y.first) return x.first del;  //存储被删除元素的下标        for(int i=0;i

2948. 交换得到字典序最小的数组

题解:如果一组数字之间总有两个数之差<=limit则这组数可以进行任意交换,也就意味着可以将其交换为有序的;所以此题就转化为了找一组数组该组数字间中有两数之差<=limit,如果直接对整个数组进行查找效率太低,此次可以向进行排序,排序后就很容易查找了,但是排序之前还要将数组元素大小与数组下标绑定,否则在后面进行交换时找不到具体下标位置。

在排序后,通过分组循环找到子数组其相邻元素之差<=limit,这样的子数组就可以进行任意交换,再根据保留的下标将下标和元素大小进行对应。

class Solution {public:    vector lexicographicallySmallestArray(vector& nums, int limit) {        //可以先将数组进行排序,根据limit判断那一组的数字是可以进行交换的        //但是在排序后数组就是乱序的,所以排序时要带上下标        int n=nums.size();        vector> tmp;        for(int i=0;i x,pair y){ return x.first ret(n);        int i=0;        while(i index;            for(int j=start;j

总结

分组循环有点类似与同向双指针,在处理分组循环类题目时关键点在于正确设计内外层循环的分工,并处理好边界条件。该模板可解决大多数需要统计连续子数组特征的竞赛题目。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/929299.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站建设竞争对数分析江苏建设集团招聘信息网站

1.2 中国高等级自动驾驶发展近况 通过对中国高等级自动驾驶行业的观察和分析&#xff0c;亿欧汽车认为&#xff0c;除技术解决方案提供商外&#xff0c;如今的车企、政府、资本同样在产业链中扮演重要角色。此外&#xff0c;车路协同技术的发展也为高等级自动驾驶的发展提供了更…

java学习日记10.5

运算符 优先级 最高括号 ( ) [ ] 后缀自增/自减 i++/i--单目运算符前缀自增/自减、正负号、按位取反、逻辑非 i++/i--、+/-、~、!强制类型转换 (int)算术运算符乘、整除、求模 *、/、% 加、减 +、-位运算符与移…

US$34.2 KEYDIY KD B11-3 Universal Flip Remote Key 3 Buttons for PSA Type 5pcs/lot

KEYDIY KD B11-3 Universal Flip Remote Key 3 Buttons for PSA Type 5pcs/lotProduct Specifications:Manufacturer: KEYDIY Condition: New Color: Black Buttons: 3 Panic: No Transponder: No Proximity / Smart /…

帮做简历哪个网站好国内最新新闻摘抄30字

关于JavaScript中日期对象使用方法&#xff1a; 一般有两种设置时间的方式&#xff1a; 一种是直接指定&#xff0c;如&#xff1a;date.setHours(13);    //指定date的时间为下午1点。 第二种是先获取时间进行计算&#xff0c;然后再进行设置&#xff0c;如&#xff1a; d…

【JNI】JNI基础语法

1 C 和 C++ 在 JNI 中的区别 ​ JNI环境搭建 中介绍了在命令行和 Android Studio 中如何编译 JNI 代码,本文将介绍 JNI 的基础语法,主要介绍 JNI 的数据类型、JNI 与 Java 交互、异常处理,参考了 JNI 官方文档,…

面试题——计算机网络:HTTP和HTTPS的区别? - 教程

面试题——计算机网络:HTTP和HTTPS的区别? - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas"…

【EF Core】通过 DbContext 选项扩展框架

本来老周计划在 10 月 1 日或 2 日写这篇水文的,没打算出去玩(确实没啥好玩)。不过因为买的运动相机到手,急着想试试效果,于是就备了些干粮,骑着山地车在外面鬼混了一天。10 月 2 日,家里来了三位热爱学习的小妹…

从Chrome渲染器代码执行到内核:MSG_OOB漏洞分析与利用

本文详细分析了Linux内核中MSG_OOB特性的安全漏洞(CVE-2025-38236),探讨了如何从Chrome渲染器沙箱中利用该漏洞实现从用户态代码执行到内核权限提升的完整攻击链,包括漏洞原理、利用技术和沙箱逃逸方法。从Chrome渲染…

assistant-ui

assistant-ui. https://langgraph.com.cn/cloud/how-tos/use_stream_react/index.htmluseStream() React hook 提供了一种将 LangGraph 无缝集成到 React 应用程序中的方式。它处理了流式传输、状态管理和分支逻辑的所…

婚纱网站怎么做临淄区最新招聘信息

grpc 与 protobuf grpc 使用的是 protobuf 协议&#xff0c;其是一个通用的 rpc 框架&#xff0c;基本支持主流的所有语言、其底层使用 http/2 进行网络通信&#xff0c;具有较高的效率 protobuf 是一种序列化格式&#xff0c;这种格式具有 序列化以及解码速度快&#xff08;…

US$34.2 KEYDIY KD B10-4 Universal Flip Remote Key 3+1 Buttons for Honda Type 5pcs/lot

KEYDIY KD B10-4 Universal Flip Remote Key 3+1 Buttons for Honda Type 5pcs/lotProduct Specifications:Manufacturer: KEYDIY Condition: New Color: Black Buttons: 4 Panic: Yes Transponder: No Proximity / Sm…

福州全网网站建设揭阳企业网页制作公司

手里有块netduino的板子&#xff0c;一直闲置未用&#xff0c;netduino具体是什么不知道的就百度吧&#xff0c;我这也不是主要讲netduino开发的&#xff0c;简单说就是用.net开发硬件&#xff0c;了解到netduino也是原来学过C#&#xff0c;当然我主要的工作还是嵌入式硬件开发…

做网站一般要了解哪些广州手机网站建设公司哪家好

在调试RK3288 Android 8.1系统遇到一个问题&#xff1a;开机启动uboot logo过渡到kernel log的过程中会花掉直到没有显示&#xff0c;再出现kernel logo。分析&#xff1a;打印串口log时发现&#xff0c;uboot阶段显示一切正常&#xff0c;进入kernel以后就开始花掉了然后变成没…

投标网站怎么做新泰做网站

原文地址&#xff1a;http://blog.csdn.net/zuochanxiaoheshang/article/details/8769198 点击阅读原文 --------------------------------------------------- Hadoop 控制输出文件命名 在一般情况下&#xff0c;Hadoop 每一个 Reducer 产生一个输出文件&#xff0c;文件以 …

《无垠的太空(2)卡利班之战》电子书素材征集

《无垠的太空(2)卡利班之战》电子书素材征集《无垠的太空(2)卡利班之战》电子书素材征集 “太空无垠”(又叫“苍穹浩瀚”)系列的第二部《卡利班之战》中文版纸质书已经出了,我想制作成电子书,哪位有pdf可以发下。或…

20251006 之所思 - 人生如梦

20251006 之所思10月6日早上9点起来,一直计划刷牙洗脸后去学英语,但是沉迷于短视频,浪费两个小时,越刷越浮躁,越刷越焦虑。浮躁是因为即时满足之后的空虚感,焦虑是因为自己计划了很多事情,但是因为一直刷手机没…

C# Avalonia 16- Animation- RotateButton

C# Avalonia 16- Animation- RotateButtonRotateButton.axaml代码<Window xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http…

US$78.85 KEYDIY KD ZB42-4 Universal Smart Remote Key 3+1 Buttons for Lexus Type 5pcs/lot

KEYDIY KD ZB42-4 Universal Smart Remote Key 3+1 Buttons for Lexus Type 5pcs/lotProduct Specifications:Manufacturer: KEYDIY Condition: New Color: Black Buttons: 4 Panic: Yes Transponder - ID: Without Tr…

2025 十一集训

/Day 1:\(2^{cn}(c<1)\) 专题选讲

详细介绍:python第31天打卡

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …