将数组拆分为三个相等的子数组
考虑一个包含 n 个整数的数组 A。确定数组 A 是否可以分成三个连续的部分,使得每个部分的总和相等。如果是,则打印任何索引对(i, j) 使得 sum(arr[0..i]) = sum(arr[i+1..j]) = sum(arr[j+1..n-1 ]),否则打印 -1。
例子:
Input : arr[] = {1, 3, 4, 0, 4}
Output : (1, 2)
Sum of subarray arr[0..1] is equal to
sum of subarray arr[2..3] and also to
sum of subarray arr[4..4]. The sum is 4.
Input : arr[] = {2, 3, 4}
Output : -1
No three subarrays exist which have equal
sum.
一个简单的解决方案是首先找到所有子数组,将这些子数组的和与它们的起点和终点存储起来,然后找到三个不相交且总和相等的连续子数组。该解决方案的时间复杂度将是二次的。
一个有效的解决方案是首先找到所有数组元素的总和 S。检查这个总和是否可以被 3 整除。这是因为如果 sum 不可整除,则 sum 不能分成三个相等的和集。如果有三个连续的子数组和相等,则每个子数组的和为 S/3。假设所需的索引对是 (i, j),使得 sum(arr[0..i]) = sum(arr[i+1..j]) = S/3。还有 sum(arr[0..i]) = preSum[i] 和 sum(arr[i+1..j]) = preSum[j] – preSum[i]。这给出了 preSum[i] = preSum[j] – preSum[i] = S/3。这给出了 preSum[j] = 2*preSum[i]。因此,问题简化为找到两个索引 i 和 j,使得 preSum[i] = S/3 和 preSum[j] = 2*(S/3)。
为了找到这两个索引,遍历数组并将总和存储到变量 preSum 中的当前元素。检查 preSum 是否等于 S/3 和 2*(S/3)。
执行:
C++
// CPP program to determine if array arr[]
// can be split into three equal sum sets.
#include
using namespace std;
// Function to determine if array arr[]
// can be split into three equal sum sets.
int findSplit(int arr[], int n)
{
int i;
// variable to store prefix sum
int preSum = 0;
// variables to store indices which
// have prefix sum divisible by S/3.
int ind1 = -1, ind2 = -1;
// variable to store sum of
// entire array.
int S;
// Find entire sum of the array.
S = arr[0];
for (i = 1; i < n; i++)
S += arr[i];
// Check if array can be split in
// three equal sum sets or not.
if(S % 3 != 0)
return 0;
// Variables to store sum S/3
// and 2*(S/3).
int S1 = S / 3;
int S2 = 2 * S1;
// Loop until second last index
// as S2 should not be at the last
for (i = 0; i < n-1; i++)
{
preSum += arr[i];
// If prefix sum is equal to S/3
// store current index.
if (preSum == S1 && ind1 == -1)
ind1 = i;
// If prefix sum is equal to 2* (S/3)
// store current index.
else if(preSum == S2 && ind1 != -1)
{
ind2 = i;
// Come out of the loop as both the
// required indices are found.
break;
}
}
// If both the indices are found
// then print them.
if (ind1 != -1 && ind2 != -1)
{
cout << "(" << ind1 << ", "
<< ind2 << ")";
return 1;
}
// If indices are not found return 0.
return 0;
}
// Driver code
int main()
{
int arr[] = { 1, 3, 4, 0, 4 };
int n = sizeof(arr) / sizeof(arr[0]);
if (findSplit(arr, n) == 0)
cout << "-1";
return 0;
}
Java
// Java program to determine if array arr[]
// can be split into three equal sum sets.
import java.io.*;
import java.util.*;
public class GFG {
// Function to determine if array arr[]
// can be split into three equal sum sets.
static int findSplit(int []arr, int n)
{
int i;
// variable to store prefix sum
int preSum = 0;
// variables to store indices which
// have prefix sum divisible by S/3.
int ind1 = -1, ind2 = -1;
// variable to store sum of
// entire array.
int S;
// Find entire sum of the array.
S = arr[0];
for (i = 1; i < n; i++)
S += arr[i];
// Check if array can be split in
// three equal sum sets or not.
if(S % 3 != 0)
return 0;
// Variables to store sum S/3
// and 2*(S/3).
int S1 = S / 3;
int S2 = 2 * S1;
// Loop until second last index
// as S2 should not be at the last
for (i = 0; i < n-1; i++)
{
preSum += arr[i];
// If prefix sum is equal to S/3
// store current index.
if (preSum == S1 && ind1 == -1)
ind1 = i;
// If prefix sum is equal to 2*(S/3)
// store current index.
else if(preSum == S2 && ind1 != -1)
{
ind2 = i;
// Come out of the loop as both the
// required indices are found.
break;
}
}
// If both the indices are found
// then print them.
if (ind1 != -1 && ind2 != -1)
{
System.out.print("(" + ind1 + ", "
+ ind2 + ")");
return 1;
}
// If indices are not found return 0.
return 0;
}
// Driver code
public static void main(String args[])
{
int []arr = { 1, 3, 4, 0, 4 };
int n = arr.length;
if (findSplit(arr, n) == 0)
System.out.print("-1");
}
}
// This code is contributed by Manish Shaw
// (manishshaw1)
Python3
# Python3 program to determine if array arr[]
# can be split into three equal sum sets.
# Function to determine if array arr[]
# can be split into three equal sum sets.
def findSplit(arr, n):
# variable to store prefix sum
preSum = 0
# variables to store indices which
# have prefix sum divisible by S/3.
ind1 = -1
ind2 = -1
# variable to store sum of
# entire array. S
# Find entire sum of the array.
S = arr[0]
for i in range(1, n):
S += arr[i]
# Check if array can be split in
# three equal sum sets or not.
if(S % 3 != 0):
return 0
# Variables to store sum S/3
# and 2*(S/3).
S1 = S / 3
S2 = 2 * S1
# Loop until second last index
# as S2 should not be at the last
for i in range(0,n-1):
preSum += arr[i]
# If prefix sum is equal to S/3
# store current index.
if (preSum == S1 and ind1 == -1):
ind1 = i
# If prefix sum is equal to 2*(S/3)
# store current index.
elif(preSum == S2 and ind1 != -1):
ind2 = i
# Come out of the loop as both the
# required indices are found.
break
# If both the indices are found
# then print them.
if (ind1 != -1 and ind2 != -1):
print ("({}, {})".format(ind1,ind2))
return 1
# If indices are not found return 0.
return 0
# Driver code
arr = [ 1, 3, 4, 0, 4 ]
n = len(arr)
if (findSplit(arr, n) == 0) :
print ("-1")
# This code is contributed by Manish Shaw
# (manishshaw1)
C#
// C# program to determine if array arr[]
// can be split into three equal sum sets.
using System;
using System.Collections.Generic;
class GFG {
// Function to determine if array arr[]
// can be split into three equal sum sets.
static int findSplit(int []arr, int n)
{
int i;
// variable to store prefix sum
int preSum = 0;
// variables to store indices which
// have prefix sum divisible by S/3.
int ind1 = -1, ind2 = -1;
// variable to store sum of
// entire array.
int S;
// Find entire sum of the array.
S = arr[0];
for (i = 1; i < n; i++)
S += arr[i];
// Check if array can be split in
// three equal sum sets or not.
if(S % 3 != 0)
return 0;
// Variables to store sum S/3
// and 2*(S/3).
int S1 = S / 3;
int S2 = 2 * S1;
// Loop until second last index
// as S2 should not be at the last
for (i = 0; i < n-1; i++)
{
preSum += arr[i];
// If prefix sum is equal to S/3
// store current index.
if (preSum == S1 && ind1 == -1)
ind1 = i;
// If prefix sum is equal to S/3
// store current index.
else if(preSum == S2 && ind1 != -1)
{
ind2 = i;
// Come out of the loop as both the
// required indices are found.
break;
}
}
// If both the indices are found
// then print them.
if (ind1 != -1 && ind2 != -1)
{
Console.Write("(" + ind1 + ", "
+ ind2 + ")");
return 1;
}
// If indices are not found return 0.
return 0;
}
// Driver code
public static void Main()
{
int []arr = { 1, 3, 4, 0, 4 };
int n = arr.Length;
if (findSplit(arr, n) == 0)
Console.Write("-1");
}
}
// This code is contributed by Manish Shaw
// (manishshaw1)
PHP
Javascript
(1, 2)
时间复杂度: O(n)
辅助空间: O(1)