数组越界与循环。

为了避免出现数组越界,建议使用i,i-1,i-2这样的变量,而非i,i+1,i+2

例如f(n)=f(n-1)+f(n-2)。

正循环都是如此。

循环的灵活使用

对于

For(变量初始化;循环继续的条件;迭代变量的移动){

}

这三个部分并不一定都要写上。你可以把它们空着,作为一个提醒。

For中i的次数可以表示轮数,但完全也可以灵活使用。

例如for(i=0;i<10;i++){

       i++;

}

I会被加快。

尤其是在双指针这类问题中,更是如此。

来看下面这样一个for循环。并且是循环嵌套。

leetcode力扣第3297题。

 for(i=0,j=0;word1[j];){  

        //每次专注分析指针j的一个元素

        numHelpArr[cti(word1[j])]++;

        flag=isEnough(chArr,numArr,chHelpArr,numHelpArr,newLen);

        if(flag==0){

            j++;

            continue;

        }

        while(true){

            ans+=len1-j;//达标就该结算一下

            numHelpArr[cti(word1[i])]--;

            i++;

            flag=isEnough(chArr,numArr,chHelpArr,numHelpArr,newLen);

            if(flag==0){

                j++;

                break;

            }

            //同指分析,提前结算

            if(i==j){

                ans+=len1-j;//提前结算

                numHelpArr[cti(word1[i])]--;

                i++;

                j++;

                break;

            }

        }

        continue;

    }

首先先来分析内层循环。直接一个死循环。当条件达到退出时再退出。

这样写有利于提高程序的灵活性。如果把flag放在while里面,很可能就无法实现功能了。

对于迭代变量I,j。通常应该先分析,再移动,以免出现越界。

例如探索指针j,就应该先分析j中的内容,再j++。

迭代变量i,i中的内容是在逐渐消退的,那么也是先对i进行消失,而后再移动i

while(true){

            ans+=len1-j;//达标就该结算一下

            numHelpArr[cti(word1[i])]--;

            i++;

            flag=isEnough(chArr,numArr,chHelpArr,numHelpArr,newLen);

            if(flag==0){

                j++;

                break;

            }

            //同指分析,提前结算

            if(i==j){

                ans+=len1-j;//提前结算

                numHelpArr[cti(word1[i])]--;

                i++;

                j++;

                break;

            }

        }

对于上面这个循环,看到其中有很多部分时相同的,我们把相同的部分用中文字代替一下

while(true){

            结算。

            I清理叛徒。

I后查。

            flag判断状态。

            if(flag==0){

                j++;

                break;

            }

            //同指分析,提前结算

            if(i==j){

               结算。

                    I清理叛徒。

I后查。

           

                j++;

                break;

            }

        }

将{

结算。

            I清理叛徒。

I后查。

}视为一个整体,称为行动1.

那么就有,

while(true){

行动1

            flag判断状态。

            if(flag==0){

                j++;

                break;

            }

            //同指分析,提前结算

            if(i==j){

                行动1

                j++;

                break;

            }

}

现在我们考量,是否有可能把while中的true给换掉呢?

do{

行动1

            flag判断状态。

            if(flag==0){

                j++;

                break;

            }

} while(i!=j)

行动1

j++;

一定程度上可以,但是并不优雅。这是因为脱离循环有两种情况。一种是flag==0.也就是因为不满足条件而导致提前结束。另一种是i==j,也就是两者同指了,马上要分析完了。应该退出了。两者不同,退出所进行的行为也不同。因此不能将其合并。如果一定要去除内部的break,就必须在离开时指出其所属的退出标记,但是这样做,可读性并不高。

那么,行为与if判断的顺序是否可以调整呢?

while(true){

行动1

            flag判断状态。

            if(flag==0){

                j++;

                break;

            }

            //同指分析,提前结算

            if(i==j){

                行动1

                j++;

                break;

            }

}

事实上可以。也就是先判断再行动。但是,由于此种情况下,无论如何都会执行一次。必须在循环外先执行一次。然后再进入内部的循环。

行动1分为几种情况,

第一种,与迭代变量i无关的。

第二种,与某个迭代变量i有关的,且是读取关系的。

第三种,与某个迭代变量i有关的,且是读后修改关系的。

如果只想读取迭代变量i,那么移动这个语句,就不要越过修改这个迭代变量的语句。

更一般地,考量下面两个语句。

语句A(读变量1,读变量2,改变量3,改变量4)

语句B(读变量1,读变量2,改变量3,改变量4)

根据读改原则,可以判断其顺序是否是可变化的。也就是改变其顺序是否会影响其结果。

为何要做顺序的改变?如果顺序可以改变,则有些行为可以被整合。那就可以进行优化。

至于外层循环,则比较普通了。

不过说到一点想法,每个循环就是一个吞噬器,不断的往后吞噬一点。有点像迭代器。有点像数学归纳法的感觉。有点自动化的感觉。循环,才是自动化节约重复工作的核心。不过,计算机本身就是为了把工程自动化的。而循环,则是自动化中的自动化。

3297. 统计重新排列后包含另一个字符串的子字符串数目 I - 力扣(LeetCode)

欢迎读者留下自己对循环的理解!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值