分组循环指的是将整个数组或者字符串分为很多片段,这些片段的判断处理逻辑是一样的。分组循环需要使用同向双指针,但是与滑动窗口不同的是,滑动窗口是收集左右区间内连续数组或者字符串,当不满足收集要求时移动右指针,而当满足后移动左指针,此时左指针移动到原来左指针的下一位,而分组循环是左指针移动到右指针下一位。
// 模板 l、r分别表示左右指针
int l=0,r=0;
while(r
思路:分组循环,相当于把字符串分为多个连续相同字符片段,利用左右端点l、r求解最长连续相同字符片段长度。
class Solution {
public:
int maxPower(string s) {
int n=s.size();
int l=0,r=0;
int res=0;
while(r
思路:分组循环,相当于把字符串分为多个连续1或者0字符片段,利用左右端点l、r和元素s[l]求解最长连续1或者0字符片段长度,再根据条件返回对应结果。
class Solution {
public:
bool checkZeroOnes(string s) {
// 分别记录最长1、最长0长度
int num1=0,num0=0;
int n=s.size();
// 区间左右端点
int l=0,r=0;
while(rnum0;
}
};
思路:分组循环,相当于把字符串分为多个连续相同片段,利用左右端点l、r求解每一个连续相同片段长度,如果长度小于3则直接将该片段加入结果,反之则只加入两个字符即可。
class Solution {
public:
string makeFancyString(string s) {
string res;
int n=s.size();
int l=0,r=0;
while(r
思路:分组循环,相当于把字符串分为多个连续A或者B字符片段,利用左右端点l、r和元素colors[l]求解最长连续A或者B字符片段可选择的次数,再根据条件返回对应结果。注意,最长连续A或者B字符片段可选择的次数为在保留左右两边字符的情况下中间所有剩余字符,即一旦长度大于等于3则为长度减去2,反之则为0,由于A是先手,故A必须严格大于B。
class Solution {
public:
bool winnerOfGame(string colors) {
int n=colors.size();
// 转换为次数
int numA=0,numB=0;
int l=0,r=0;
while(r=3 则可移动的为长度减去左右两边2
if(colors[l]=='A')
numA+=(r-l+1)>=3?(r-l+1)-2:0;
else
numB+=(r-l+1)>=3?(r-l+1)-2:0;
r++;
}
return numA>numB;
}
};
思路:分组循环,相当于把字符串分为多个连续相同片段,利用左右端点l、r求解每一个连续相同片段长度,然后利用1、3、6、10、15…规律根据长度n求出方案数n*(n+1)/2,最后累计方案数即可。
class Solution {
public:
const long long NUM=1e9+7;
int countHomogenous(string s) {
// 1 3 6 10 15 n*(n+1)/2
int n=s.size();
int l=0,r=0;
// long long 避免精度不够
long long res=0;
while(r
思路:分组循环,相当于把数组分为多个连续公差为1的递减片段,利用左右端点l、r求解每一个连续公差为1的递减片段长度,然后利用1、3、6、10、15…规律根据长度n求出方案数n*(n+1)/2,最后累计方案数即可。
class Solution {
public:
long long getDescentPeriods(vector& prices) {
int n=prices.size();
int l=0,r=0;
long long res=0;
while(r
思路:分组循环,相当于把绳子分为多个连续相同气球片段,利用左右端点l、r求解每一个连续相同气球片段,并对每个大于1的片段求解总时间和最大时间从而得到最小时间,对这些时间累加即可得到结果。
class Solution {
public:
int minCost(string colors, vector& neededTime) {
int n=colors.size();
int l=0,r=0;
int res=0;
while(r
思路:分组循环,相当于把字符串分为多个按照元音字母递增的至少含有所有元音字母各一个的字符串,与前面几题不同的是,该题需要在记录符合区间的同时,也使用uset来记录元音字母个数,从而便于后序收集结果条件各个元音字母至少一个的判断。
class Solution {
public:
int longestBeautifulSubstring(string word) {
int n=word.size();
int l=0,r=0;
int res=0;
while(r uset;
// 按照 a e i o u顺序
while(r=word[r])
{
uset.emplace(word[r]);
r++;
}
// 加入最后一个 前几题都是只需r++ 不需额外处理
uset.emplace(word[r]);
// cout<
思路:分组循环,相当于把数组分为多个[l,r]区间,其中求出满足题目要求的长度最长的[l,r]区间。该题与上述题目不同的地方在于,该题中存在l、[l,r-1]、[l,r]三个判断,由于此处的差异就会导致在处理判断边界条件时可能会出现些许差异和错误。此处首先对于l不满足的情况进行特殊处理,由于已经处理过l,那么后续就是在l满足条件的情况下进行,此时将r加一,相当于比较r和r-1,而不是原先的r和r+1,那么相应的此处得到的r就是第一个不满足的,对应的长度变为r-l,同时也不需要继续对r++啦。(注意细节)
class Solution {
public:
int longestAlternatingSubarray(vector& nums, int threshold) {
int n=nums.size();
int l=0,r=0;
int res=0;
while(rthreshold)
{
// continue之前记得r++啊否则区间不动
r++;
continue;
}
// 此处才更新左区间
l=r;
// 左区间已经满足 此时r+1
r+=1;
// r是第一个不满足的 故此时长度为r-l 并且后续不需要r++
while(r
思路:分组循环,相当于把数组分为多个[l,r]区间,其中求出满足题目要求的长度最长的[l,r]区间。该题与2760不同的地方在于,该题所分得的区间可能重叠喔,比如2 3 4 3 4,其中2 3和3 4 3 4其重叠一个,但是其最多也只会重叠一个,故我们找到第一个不满足的r后回退1即可。建议在分组循环类别的题目中,遇到给区间[l,r]设置条件时先对首部条件进行不合法判断处理再继续喔!
class Solution {
public:
int alternatingSubarray(vector& nums) {
int n=nums.size();
int l=0,r=0;
int res=-1;
// 数组长度至少为2!!!
while(r+1
总结:灵老师的nums[i]==nums[i0+(i-i0)%2]也很灵性!!!
思路:分组循环,相当于把字符串分为多个连续公差为1的递增片段,利用左右端点l、r求解每一个连续公差为1的递增片段两端,并按照要求格式加入结果。
class Solution {
public:
vector summaryRanges(vector& nums) {
int n=nums.size();
int r=0,l;
string tmp;
vector res;
// l 左端點 r右端點 同向雙指針
while(r"+to_string(nums[r]);
res.push_back(tmp);
r++;
}
return res;
}
};
有一说一,虽然现在力扣刷了四百多题,牛客刷了两百多题,包括前端和算法,但还是觉得遇到一些脑筋急转弯的简单或者中等题还是不会,对于一些题型也没有形成自己的解题思路逻辑,遇到困难题也是要看题解才行,除非自己刷过几次,感觉好挫败啊呜呜呜呜呜呜呜呜,要怎么办!!!