写在前面
一道很艺术的编程题~做学习记录
题目描述
给定一个正整数数组 nums和整数 k 。
请找出该数组内乘积小于 k 的连续的子数组的个数。
示例
示例1:
输入: nums = [10,5,2,6], k = 100
输出: 8
解释: 8个乘积小于100的子数组分别为: [10], [5], [2], [6], [10,5], [5,2], [2,6], [5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于100的子数组。_
示例 2:
输入: nums = [1,2,3], k = 0
输出: 0
提示
1 < = n u m s . l e n g t h < = 3 ∗ 1 0 4 1 <= nums.length <= 3 * 10^4 1<=nums.length<=3∗104
1 < = n u m s [ i ] < = 1000 1 <= nums[i] <= 1000 1<=nums[i]<=1000
0 < = k < = 1 0 6 0 <= k <=10^6 0<=k<=106
解题思路
这道题使用双指针(活动窗口来解答)
双指针(
l
e
f
t
,
r
i
g
h
t
left,right
left,right)分别指向窗口的左右。由于
0
<
=
k
<
=
1
0
6
0 <= k <=10^6
0<=k<=106,故
l
e
f
t
left
left右移,乘积一定减小,
r
i
g
h
t
right
right右移,乘积一定增大。
首先,我们要明确当
r
i
g
h
t
>
n
u
m
s
.
l
e
n
g
t
h
right>nums.length
right>nums.length时结束寻找.
l
e
f
t
,
r
i
g
h
t
left,right
left,right初始值为
0
0
0。
r
i
g
h
t
right
right指向的值为最新加入窗口的值
1.如果,
r
i
g
h
t
right
right指向的值大于等于
k
k
k,则不必再相乘,直接右移
r
i
g
h
t
,
l
e
f
t
right,left
right,left值。乘积置
1
1
1.
2.如果,
r
i
g
h
t
right
right指向的值小于
k
k
k,则更新乘积。
2.1若乘积小于
k
k
k,则右移
r
i
g
h
t
right
right值,此时以新加入的
r
i
g
h
t
right
right值为结束的区间都是答案(举个栗子:
n
u
m
s
=
[
10
,
5
,
2
,
6
]
,
k
=
100
nums = [10,5,2,6], k = 100
nums=[10,5,2,6],k=100时,当
l
e
f
t
left
left指向
5
5
5,
r
i
g
h
t
right
right指向
6
6
6时,乘积为
60
(
<
100
)
60(<100)
60(<100),此时,
[
5
]
,
[
2
]
,
[
5
,
2
]
,
[
5
,
2
,
6
]
,
[
2
,
6
]
,
[
6
]
[5],[2],[5,2],[5,2,6],[2,6],[6]
[5],[2],[5,2],[5,2,6],[2,6],[6]乘积均小于100,但之前的区间为
[
5
,
2
]
[5,2]
[5,2],以2结尾的区间[2],[5,2]已经j记录到结果中了,同理,区间以5结尾时,记录过
[
5
]
[5]
[5];此时,以6结尾的区间
[
5
,
2
,
6
]
,
[
2
,
6
]
,
[
6
]
[5,2,6],[2,6],[6]
[5,2,6],[2,6],[6]是新增的答案。那么新增的个数如何计算呢,我们可以看到,当区间为
[
5
,
2
,
6
]
[5,2,6]
[5,2,6]时,left,right分别指向
5
,
6
5,6
5,6,而而新增答案以6为结尾,向左边扩增,每次扩增一位,直至区间结束(
[
6
]
,
[
2
,
6
]
,
[
5
,
2
,
6
]
[6],[2,6],[5,2,6]
[6],[2,6],[5,2,6]恰好是区间长度(
r
i
g
h
t
−
l
e
f
t
+
1
right-left+1
right−left+1)))
2.2若乘积大于
k
k
k,则右移
l
e
f
t
left
left值,减小乘积,直至乘积小于
k
k
k值为止。
代码实现
C++
class Solution {
public:
int numSubarrayProductLessThanK(vector<int>& nums, int k) {
int l = 0;
int prod = 1; //存储乘积
int res = 0;
for(int r = 0; r < nums.size(); r++){
if(nums[r]>k){
l=r+1;
prod=1;
continue;
}
prod *= nums[r];
while(prod >= k){
prod /= nums[l++];
}
res += r - l + 1;
}
return res;
}
};