最后更新于
最后更新于
给定一个正整数数组 nums。
找出该数组内乘积小于 k 的连续的子数组的个数。
示例 1:
说明:
0 < nums.length <= 50000
0 < nums[i] < 1000
0 <= k < 10^6
先对原数组中的每个数字进行对数转换, 然后求得完整的前缀和数组, 然后求每个区间所有元素的连乘结果, 就是前缀数组对应位置之差, 这点与560题中一样. 不一样的是, 560题中只需要找到前缀和为差值为k
的前缀位置, 所以可以用哈希边遍历, 边存储, 边判断. 但本题是要找到所有小于k
的子数组, 看起来还是要对每个位置再遍历其开头(或结尾)的所有子数组, 一个个进行判别, 但前缀和数组的递增的特殊性质, 让我们可以用二分的方法进行优化.
可以参考中的方法, 使用前缀和解题. 连乘经过的转换, 就转换成了连加. 而且由于题目中数组的长度和每个元素的大小情况, 很容易出现溢出的情况, 而转换也解决了这个问题.
对于每个位置, 假设我们要遍历以这个数字作为开头的子数组, 是否满足连乘小于, 我们可以对前缀和数组从的位置开始, 寻找值所处的位置, 小于这个数字的位置, 代表的从(包含)到这个位置组成的子数组, 其连乘结果肯定是小于k的, 因此如果我们用二分数组在前缀和数组上找到的位置为, 则以位置开头的子数组满足要求的数量为.
对于每个, 我们要找到满足条件的最小的.满足 . 对于更靠右的, 其对应的最小的, 不可能小于靠左的对应的. 因此可以使用双指针, 移动右指针的同时, 不断调整左指针的位置.
我们使用一重循环枚举 ,同时设置 的初始值为 0。在循环的每一步中,表示 向右移动了一位,将乘积乘以 。此时我们需要向右移动 ,直到满足乘积小于 的条件。在每次移动时,需要将乘积除以 。当 移动完成后,对于当前的 ,就包含了 个乘积小于 的连续子数组。