给定两个数组A[]和B[] ,以及一个整数K ,任务是找到选择两个相同大小的子数组的方法数,一个来自 A,另一个来自 B,这样子数组至少有K 相等的元素对。 (即两个选定子阵列中的对 (A[i], B[j]) 的数量,使得 A[i] = B[j] >= K)。
例子:
Input: A[] = {1, 2}, B[] = {1, 2, 3}, K = 1
Output: 4
The ways to select two subarrays are:
- [1], [1]
- [2], [2]
- [1, 2], [1, 2]
- [1, 2], [2, 3]
Input: A[] = {3, 2, 5, 21, 15, 2, 6}, B[] = {2, 1, 4, 3, 6, 7, 9}, K = 2
Output: 7
方法:
- 不是分别处理这两个数组,让我们以二进制矩阵的形式组合它们,使得:
mat[i][j] = 0, if A[i] != B[j]
= 1, if A[i] = B[j]
- 现在,如果我们考虑这个矩阵的任何子矩阵,比如大小为 P × Q,它基本上是大小为 P 的 A 的子数组和大小为 Q 的 B 的子数组的组合。 由于我们只想检查大小相等的子数组,我们将只考虑平方子矩阵。
- 让我们考虑一个正方形子矩阵,左上角为 (i, j),右下角为 (i + size,, j + size)。这相当于考虑子数组 A[i: i + size] 和 B[j: j + size]。可以观察到,如果这两个子阵列将有 x 对相等的元素,那么子矩阵中将有 x 1。
- 因此遍历矩阵 (i, j) 的所有元素并将它们视为正方形的右下角。现在,一种方法是遍历子矩阵的所有可能大小并找到总和 >= k 的大小,但这会降低效率。可以观察到,如果一个以 (i, j) 为右下角的 S x S 子矩阵的总和 >= k,那么所有大小为 >= S 且 (i, j) 为右下角的方形子矩阵将遵循财产。
- 因此,不是在每个 (i, j) 处迭代所有大小,我们将只对正方形子矩阵的大小应用二分搜索并找到最小的大小 S,使其总和 >= K,然后简单地将矩阵相加更大的边长。
可以参考这篇文章,看看如何使用 2D 前缀和在恒定时间内评估子矩阵和。
下面是上述方法的实现:
C++
// C++ implementation to count the
// number of ways to select equal
// sized subarrays such that they
// have atleast K common elements
#include
using namespace std;
// 2D prefix sum for submatrix
// sum query for matrix
int prefix_2D[2005][2005];
// Function to find the prefix sum
// of the matrix from i and j
int subMatrixSum(int i, int j, int len)
{
return prefix_2D[i][j] -
prefix_2D[i][j - len] -
prefix_2D[i - len][j] +
prefix_2D[i - len][j - len];
}
// Function to count the number of ways
// to select equal sized subarrays such
// that they have atleast K common elements
int numberOfWays(int a[], int b[], int n,
int m, int k)
{
// Combining the two arrays
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (a[i - 1] == b[j - 1])
prefix_2D[i][j] = 1;
else
prefix_2D[i][j] = 0;
}
}
// Calculating the 2D prefix sum
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
prefix_2D[i][j] += prefix_2D[i][j - 1];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
prefix_2D[i][j] += prefix_2D[i - 1][j];
}
}
int answer = 0;
// iterating through all
// the elements of matrix
// and considering them to
// be the bottom right
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
// applying binary search
// over side length
int low = 1;
int high = min(i, j);
while (low < high) {
int mid = (low + high) >> 1;
// if sum of this submatrix >=k then
// new search space will be [low, mid]
if (subMatrixSum(i, j, mid) >= k) {
high = mid;
}
// else new search space
// will be [mid+1, high]
else {
low = mid + 1;
}
}
// Adding the total submatrices
if (subMatrixSum(i, j, low) >= k) {
answer += (min(i, j) - low + 1);
}
}
}
return answer;
}
// Driver Code
int main()
{
int N = 2, M = 3;
int A[N] = { 1, 2 };
int B[M] = { 1, 2, 3 };
int K = 1;
cout << numberOfWays(A, B, N, M, K);
return 0;
}
Java
// Java implementation to count the
// number of ways to select equal
// sized subarrays such that they
// have atleast K common elements
class GFG{
// 2D prefix sum for submatrix
// sum query for matrix
static int [][]prefix_2D = new int[2005][2005];
// Function to find the prefix sum
// of the matrix from i and j
static int subMatrixSum(int i, int j, int len)
{
return prefix_2D[i][j] -
prefix_2D[i][j - len] -
prefix_2D[i - len][j] +
prefix_2D[i - len][j - len];
}
// Function to count the number of ways
// to select equal sized subarrays such
// that they have atleast K common elements
static int numberOfWays(int a[], int b[], int n,
int m, int k)
{
// Combining the two arrays
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if (a[i - 1] == b[j - 1])
prefix_2D[i][j] = 1;
else
prefix_2D[i][j] = 0;
}
}
// Calculating the 2D prefix sum
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
prefix_2D[i][j] += prefix_2D[i][j - 1];
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
prefix_2D[i][j] += prefix_2D[i - 1][j];
}
}
int answer = 0;
// Iterating through all
// the elements of matrix
// and considering them to
// be the bottom right
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
// Applying binary search
// over side length
int low = 1;
int high = Math.min(i, j);
while (low < high)
{
int mid = (low + high) >> 1;
// If sum of this submatrix >=k then
// new search space will be [low, mid]
if (subMatrixSum(i, j, mid) >= k)
{
high = mid;
}
// Else new search space
// will be [mid+1, high]
else
{
low = mid + 1;
}
}
// Adding the total submatrices
if (subMatrixSum(i, j, low) >= k)
{
answer += (Math.min(i, j) - low + 1);
}
}
}
return answer;
}
// Driver Code
public static void main(String[] args)
{
int N = 2, M = 3;
int A[] = { 1, 2 };
int B[] = { 1, 2, 3 };
int K = 1;
System.out.print(numberOfWays(A, B, N, M, K));
}
}
// This code is contributed by Princi Singh
Python3
# Python3 implementation to count the
# number of ways to select equal
# sized subarrays such that they
# have atleast K common element
# 2D prefix sum for submatrix
# sum query for matrix
prefix_2D = [[0 for x in range (2005)]
for y in range (2005)]
# Function to find the prefix sum
# of the matrix from i and j
def subMatrixSum(i, j, length):
return (prefix_2D[i][j] -
prefix_2D[i][j - length] -
prefix_2D[i - length][j] +
prefix_2D[i - length][j - length])
# Function to count the number of ways
# to select equal sized subarrays such
# that they have atleast K common elements
def numberOfWays(a, b, n, m, k):
# Combining the two arrays
for i in range (1, n + 1):
for j in range (1, m + 1):
if (a[i - 1] == b[j - 1]):
prefix_2D[i][j] = 1
else:
prefix_2D[i][j] = 0
# Calculating the 2D prefix sum
for i in range (1, n + 1):
for j in range (1, m + 1):
prefix_2D[i][j] += prefix_2D[i][j - 1]
for i in range (1, n + 1):
for j in range (1, m + 1):
prefix_2D[i][j] += prefix_2D[i - 1][j]
answer = 0
# iterating through all
# the elements of matrix
# and considering them to
# be the bottom right
for i in range (1, n +1):
for j in range (1, m + 1):
# applying binary search
# over side length
low = 1
high = min(i, j)
while (low < high):
mid = (low + high) >> 1
# if sum of this submatrix >=k then
# new search space will be [low, mid]
if (subMatrixSum(i, j, mid) >= k):
high = mid
# else new search space
# will be [mid+1, high]
else:
low = mid + 1
# Adding the total submatrices
if (subMatrixSum(i, j, low) >= k):
answer += (min(i, j) - low + 1)
return answer
# Driver Code
if __name__ == "__main__":
N = 2
M = 3
A = [1, 2]
B = [1, 2, 3]
K = 1
print (numberOfWays(A, B, N, M, K))
# This code is contributed by Chitranayal
C#
// C# implementation to count the
// number of ways to select equal
// sized subarrays such that they
// have atleast K common elements
using System;
class GFG{
// 2D prefix sum for submatrix
// sum query for matrix
static int [,]prefix_2D = new int[2005, 2005];
// Function to find the prefix sum
// of the matrix from i and j
static int subMatrixSum(int i, int j, int len)
{
return prefix_2D[i, j] -
prefix_2D[i, j - len] -
prefix_2D[i - len, j] +
prefix_2D[i - len, j - len];
}
// Function to count the number of ways
// to select equal sized subarrays such
// that they have atleast K common elements
static int numberOfWays(int []a, int []b, int n,
int m, int k)
{
// Combining the two arrays
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if (a[i - 1] == b[j - 1])
prefix_2D[i, j] = 1;
else
prefix_2D[i, j] = 0;
}
}
// Calculating the 2D prefix sum
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
prefix_2D[i, j] += prefix_2D[i, j - 1];
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
prefix_2D[i, j] += prefix_2D[i - 1, j];
}
}
int answer = 0;
// Iterating through all
// the elements of matrix
// and considering them to
// be the bottom right
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
// Applying binary search
// over side length
int low = 1;
int high = Math.Min(i, j);
while (low < high)
{
int mid = (low + high) >> 1;
// If sum of this submatrix >=k then
// new search space will be [low, mid]
if (subMatrixSum(i, j, mid) >= k)
{
high = mid;
}
// Else new search space
// will be [mid+1, high]
else
{
low = mid + 1;
}
}
// Adding the total submatrices
if (subMatrixSum(i, j, low) >= k)
{
answer += (Math.Min(i, j) - low + 1);
}
}
}
return answer;
}
// Driver Code
public static void Main(String[] args)
{
int N = 2, M = 3;
int []A = { 1, 2 };
int []B = { 1, 2, 3 };
int K = 1;
Console.Write(numberOfWays(A, B, N, M, K));
}
}
// This code is contributed by Princi Singh
Javascript
输出:
4
时间复杂度: O(N * M * log(max(N, M)))