leetcode题目,713. 乘积小于 K 的子数组

这一题很容易想到滑动窗口,但是最难的是如何计算存入连续子数组的数量,(注意是连续的,否则想半天不知道怎么搞,心态炸裂)

代码与解释如下:

public int numSubarrayProductLessThanK(int[] nums, int k) {

        int l=0;/*定义左边界*/
        int count=0;/*所求的有效子数组的个数*/
        int prod=1;/*有效子数组乘积*/
        for(int r=0;r<nums.length;r++){/*定义右边界*/
            prod*=nums[r];/*实质是[l,r]范围内元素的乘积*/
            while(l<=r&&prod>=k){/*当乘积>=目标值k时,l边界右移,最坏情况是移动到了r处,表示没有满足条件的子数组*/
                prod/=nums[l];/*每移动一位,就得到新的乘积,新的乘积一定是变小的(或不变)*/
                l++;/*l右移*/
            }
            count+=r-l+1;/*这一步为什么请看下面解释*/
        }
        if(count==0){/*如果为0,表示没有满足题意的子数组,返回0*/
            return 0;
        }
        return count;


//        1.假设一个数组中有n个元素,那么它的连续子数组(请注意连续两个字)个数有1+2+···+n之和个;
//        2.我们只计算包含右边界的连续子数组,那么就是r-l+1个,这是可以被证明的,以下面为例:
//            例如[1,2,3,4,5]
//             其包含右边界为5的连续子数组分别是[5],[4,5],[3,4,5],[2,3,4,5],[1,2,3,4,5],只有这五个。
//        3.问题是我为什么只计算包含右边界的连续子数组呢,答案就是为了不和前面的子数组重复,举例说明
//                还是上面的例子,假设目标值k=24,下面模拟代码运行过程:
//        (1) l=0,r=0;所得数组[1],包含右边界1的连续子数组是他本身[1];
//        (2) l=0,r=1;所得数组[1,2],包含右边界2的连续子数组是[1,2],[2];
//        (3) l=0,r=2;所得数组[1,2,3],包含右边界2的连续子数组是[1,2,3],[2,3],[3];
//        (4) l=0,r=3;所得数组[1,2,3,4],发现乘积=24,满足while循环条件,因此左边界右移两个单位
//            l=2,r=3;所得数组[3,4],包含右边界4的连续子数组是[3,4],[4];
//        (5) l=2,r=4;所得数组[3,4,5],发现乘积>24,满足while循环条件,因此左边界右移一个单位
//            l=3,r=4;所得数组[4,5],包含右边界5的连续子数组是[4,5],[5];
//        (6)  跳出循环
//        4.总之,只算包含右边界的连续子数组,因为(不是右边界的前面已经遍历当成右边界)算过一次了。

    }

 

posted @ 2022-05-06 16:46  学习没什么用  阅读(30)  评论(0)    收藏  举报