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.总之,只算包含右边界的连续子数组,因为(不是右边界的前面已经遍历当成右边界)算过一次了。 }