具有给定产品的子数组的数量
给定一个正数数组和一个数 k,找出乘积正好等于 k 的子数组的数量。我们可以假设没有溢出。
例子 :
Input : arr = [2, 1, 1, 1, 4, 5]
k = 4
Output : 4
1st subarray : arr[1..4]
2nd subarray : arr[2..4]
3rd subarray : arr[3..4]
4th subarray : arr[4]
Input : arr = [1, 2, 3, 4, 1]
k = 24
Output : 4
1st subarray : arr[0..4]
2nd subarray : arr[1..4]
3rd subarray : arr[1..3]
4th subarray : arr[0..3]
一个简单的解决方案是考虑所有子数组并找到它们的乘积。对于每个产品,检查它是否等于 k。如果是,则增加结果。
一个有效的解决方案是使用滑动窗口技术来解决问题。我们用两个指针 start 和 end 来表示滑动窗口的起点和终点。
最初 start 和 end 都指向数组的开头,即索引 0。继续递增 end 直到 product p < k。一旦 p 等于 k 停止递增 end 并检查 end 的当前位置是否跟在数组中的一系列 1 之后。如果是,那么那些 1 也将有助于子数组计数。将这些后续 1 的计数存储在变量 countOnes 中。在此之后继续递增 start 直到 p 等于 k,同时将 (countOnes + 1) 添加到结果。如果 start 与 end 重合,则再次从递增 end 开始并遵循相同的过程。这样做直到 end < 数组大小。
为什么 countOnes + 1 被添加到结果中?
考虑上述示例案例中的第二个测试案例。如果我们按照上面提到的过程,那么在增加 end 之后,我们将到达 start = 0 和 end = 3。在此之后 countOnes 被设置为等于 1。 start = 0 有多少子数组?有两个子数组:arr[0..3] 和 arr[0..4]。观察 subarray[0..3] 是我们使用滑动窗口技术发现的。这会将结果计数增加 1,并且在表达式 countOnes + 1 中由 + 1 表示。另一个子数组 [0..4] 只需通过将单个 1 附加到子数组 [0..3] 来获得,即添加 countOnes 数1s 一次。让我们试着概括一下。假设 arr[0..i] 是使用滑动窗口技术获得的子数组,并且让 countOnes = j。然后我们可以通过将单个 1 附加到该子数组来一次将该子数组扩展单位长度。将单个 1 附加到 arr[0..i] 后,新的子数组是 arr[0..i+1] 并且结果也增加了 1。countOnes 现在减少 1 并等于 j – 1。我们可以连续追加单个一次 1 并获得一个新的子数组,直到 countOnes 不等于 0。
因此,结果计数增加了 countOnes,并在表达式 countOnes + 1 中表示为 countOnes。因此,对于 start 中的每个增量,直到 p 等于 k,只需将 countOnes + 1 添加到结果中。
请注意,上述算法不适用于 k = 1 的情况。例如,考虑测试用例 arr[] = {2, 1, 1, 1}。感谢Jeel Santoki提供这个测试用例。对于 k = 1 的情况,我们将找到所有元素为 1 的数组的每个段的长度。设 1 的特定段的长度为 x。该段的子数组数将为 x*(x+1)/2。所有这些子数组都将具有乘积 1,因为所有元素都是 1。在给定的测试用例中,从索引 1 到索引 3 只有一个段为 1,长度为 3。因此,乘积为 1 的子数组的总数为 (3*4)/2 = 6 .
该算法可以列举为:
For k != 1:
1. Initialize start = end = 0
2. Initialize res = 0, p = 1
3. Increment end until p < k
4. When p = k do:
Set countOnes = number of succeeding ones
res += (countOnes+1)
Increment start until p = k
and do res += (countOnes+1)
5. Stop if end = n
For k = 1:
1. Find all segments in array in which
only 1 is present.
2. Find length of each segment.
3. Add length*(length+1) / 2 to result.
执行:
C++
// C++ program to find number of subarrays
// having product exactly equal to k.
#include
using namespace std;
// Function to find number of subarrays
// having product equal to 1.
int countOne(int arr[], int n){
int i = 0;
// To store number of ones in
// current segment of all 1s.
int len = 0;
// To store number of subarrays
// having product equal to 1.
int ans = 0;
while(i < n){
// If current element is 1, then
// find length of segment of 1s
// starting from current element.
if(arr[i] == 1){
len = 0;
while(i < n && arr[i] == 1){
i++;
len++;
}
// add number of possible
// subarrays of 1 to result.
ans += (len*(len+1)) / 2;
}
i++;
}
return ans;
}
/// Function to find number of subarrays having
/// product exactly equal to k.
int findSubarrayCount(int arr[], int n, int k)
{
int start = 0, endval = 0, p = 1,
countOnes = 0, res = 0;
while (endval < n)
{
p *= (arr[endval]);
// If product is greater than k then we need to decrease
// it. This could be done by shifting starting point of
// sliding window one place to right at a time and update
// product accordingly.
if(p > k)
{
while(start <= endval && p > k)
{
p /= arr[start];
start++;
}
}
if(p == k)
{
// Count number of succeeding ones.
countOnes = 0;
while(endval + 1 < n && arr[endval + 1] == 1)
{
countOnes++;
endval++;
}
// Update result by adding both new subarray
// and effect of succeeding ones.
res += (countOnes + 1);
// Update sliding window and result according
// to change in sliding window. Here preceding
// 1s have same effect on subarray as succeeding
// 1s, so simply add.
while(start <= endval && arr[start] == 1 && k!=1)
{
res += (countOnes + 1);
start++;
}
// Move start to correct position to find new
// subarray and update product accordingly.
p /= arr[start];
start++;
}
endval++;
}
return res;
}
// Driver code
int main()
{
int arr1[] = { 2, 1, 1, 1, 3, 1, 1, 4};
int n1 = sizeof(arr1) / sizeof(arr1[0]);
int k = 1;
if(k != 1)
cout << findSubarrayCount(arr1, n1, k) << "\n";
else
cout << countOne(arr1, n1) << "\n";
int arr2[] = { 2, 1, 1, 1, 4, 5};
int n2 = sizeof(arr2) / sizeof(arr2[0]);
k = 4;
if(k != 1)
cout << findSubarrayCount(arr2, n2, k) << "\n";
else
cout << countOne(arr2, n2) << "\n";
return 0;
}
Java
// Java program to find number of subarrays
// having product exactly equal to k.
import java.util.*;
class GFG
{
// Function to find number of subarrays having
// product exactly equal to k.
public static int findSubarrayCount(int arr[], int n, int k)
{
int start = 0, endval = 0;
int p = 1, countOnes = 0, res = 0;
while(endval < n)
{
p *= (arr[endval]);
// If product is greater than k then we need
// to decrease it. This could be done by shifting
// starting point of sliding window one place
// to right at a time and update product accordingly.
if (p > k)
{
while (start <= endval && p > k)
{
p /= arr[start];
start++;
}
}
if (p == k)
{
// Count number of succeeding ones.
countOnes = 0;
while (endval + 1 < n && arr[endval + 1] == 1)
{
countOnes++;
endval++;
}
// Update result by adding both new
// subarray and effect of succeeding ones.
res += (countOnes + 1);
// Update sliding window and result according
// to change in sliding window. Here preceding
// 1s have same effect on subarray as succeeding
// 1s, so simply add.
while (start <= endval && arr[start] == 1)
{
res += (countOnes + 1);
start++;
}
// Move start to correct position to find new
// subarray and update product accordingly.
p /= arr[start];
start++;
}
endval++;
}
return res;
}
// Driver code
public static void main (String[] args)
{
int arr[] = new int[]{ 2, 1, 1, 1, 4, 5 };
int n = arr.length;
int k = 4;
System.out.println(findSubarrayCount(arr, n, k));
}
}
Python3
# Python3 program to find number of subarrays
# having product exactly equal to k.
# Function to find number of subarrays
# having product equal to 1.
def countOne(arr, n) :
i = 0
# To store number of ones in
# current segment of all 1s.
Len = 0
# To store number of subarrays
# having product equal to 1.
ans = 0
while(i < n) :
# If current element is 1, then
# find length of segment of 1s
# starting from current element.
if(arr[i] == 1) :
Len = 0
while(i < n and arr[i] == 1) :
i += 1
Len += 1
# add number of possible
# subarrays of 1 to result.
ans += (Len*(Len+1)) // 2
i += 1
return ans
# Function to find number of subarrays having
# product exactly equal to k.
def findSubarrayCount(arr, n, k) :
start, endval, p, countOnes, res = 0, 0, 1, 0, 0
while (endval < n) :
p = p * (arr[endval])
# If product is greater than k then we need to decrease
# it. This could be done by shifting starting point of
# sliding window one place to right at a time and update
# product accordingly.
if(p > k) :
while(start <= endval and p > k) :
p = p // arr[start]
start += 1
if(p == k) :
# Count number of succeeding ones.
countOnes = 0
while endval + 1 < n and arr[endval + 1] == 1 :
countOnes += 1
endval += 1
# Update result by adding both new subarray
# and effect of succeeding ones.
res += (countOnes + 1)
# Update sliding window and result according
# to change in sliding window. Here preceding
# 1s have same effect on subarray as succeeding
# 1s, so simply add.
while(start <= endval and arr[start] == 1 and k!=1) :
res += (countOnes + 1)
start += 1
# Move start to correct position to find new
# subarray and update product accordingly.
p = p // arr[start]
start += 1
endval += 1
return res
arr1 = [ 2, 1, 1, 1, 3, 1, 1, 4 ]
n1 = len(arr1)
k = 1
if(k != 1) :
print(findSubarrayCount(arr1, n1, k))
else :
print(countOne(arr1, n1))
arr2 = [ 2, 1, 1, 1, 4, 5]
n2 = len(arr2)
k = 4
if(k != 1) :
print(findSubarrayCount(arr2, n2, k))
else :
print(countOne(arr2, n2))
# This code is contributed by divyesh072019
C#
// C# program to find number
// of subarrays having product
// exactly equal to k.
using System;
class GFG
{
// Function to find number of
// subarrays having product
// exactly equal to k.
public static int findSubarrayCount(int []arr,
int n, int k)
{
int start = 0, endval = 0;
int p = 1, countOnes = 0, res = 0;
while(endval < n)
{
p *= (arr[endval]);
// If product is greater than k
// then we need to decrease it.
// This could be done by shifting
// starting point of sliding window
// one place to right at a time and
// update product accordingly.
if (p > k)
{
while (start <= endval && p > k)
{
p /= arr[start];
start++;
}
}
if (p == k)
{
// Count number of
// succeeding ones.
countOnes = 0;
while (endval + 1 < n &&
arr[endval + 1] == 1)
{
countOnes++;
endval++;
}
// Update result by adding
// both new subarray and
// effect of succeeding ones.
res += (countOnes + 1);
// Update sliding window and
// result according to change
// in sliding window. Here
// preceding 1s have same
// effect on subarray as
// succeeding 1s, so simply add.
while (start <= endval &&
arr[start] == 1)
{
res += (countOnes + 1);
start++;
}
// Move start to correct position
// to find new subarray and update
// product accordingly.
p /= arr[start];
start++;
}
endval++;
}
return res;
}
// Driver code
public static void Main ()
{
int []arr = new int[]{ 2, 1, 1,
1, 4, 5 };
int n = arr.Length;
int k = 4;
Console.WriteLine(findSubarrayCount(arr, n, k));
}
}
// This code is contributed by anuj_67.
PHP
$k)
{
while($start <= $endval && $p > $k)
{
$p /= $arr[$start];
$start++;
}
}
if($p == $k)
{
// Count number of
// succeeding ones.
$countOnes = 0;
while($endval + 1 < $n &&
$arr[$endval + 1] == 1)
{
$countOnes++;
$endval++;
}
// Update result by adding
// both new subarray and
// effect of succeeding ones.
$res += ($countOnes + 1);
// Update sliding window and
// result according to change
// in sliding window. Here
// preceding 1s have same
// effect on subarray as
// succeeding 1s, so simply
// add.
while($start <= $endval &&
$arr[$start] == 1)
{
$res += ($countOnes + 1);
$start++;
}
// Move start to correct
// position to find new
// subarray and update
// product accordingly.
$p /= $arr[$start];
$start++;
}
$endval++;
}
return $res;
}
// Driver Code
$arr = array(2, 1, 1, 1, 4, 5);
$n = sizeof($arr) ;
$k = 4;
echo findSubarrayCount($arr, $n, $k);
// This code is contributed by aj_36
?>
Javascript
9
4
时间复杂度: O(n)
辅助空间: O(1)