Formatted question description: https://leetcode.ca/all/805.html

# 805. Split Array With Same Average (Hard)

In a given integer array A, we must move every element of A to either list B or list C. (B and C initially start empty.)

Return true if and only if after such a move, it is possible that the average value of B is equal to the average value of C, and B and C are both non-empty.

Example :
Input:
[1,2,3,4,5,6,7,8]
Output: true
Explanation: We can split the array into [1,4,5,8] and [2,3,6,7], and both of them have the average of 4.5.


Note:

• The length of A will be in the range [1, 30].
• A[i] will be in the range of [0, 10000].

Related Topics:
Math

## Solution 1. Brute Force

Our goal is to find a non-empty subsequence B which satisfies Sum(B) * N == Sum(A) * Len(B), where N is the length of A.

We can try to get all the sums of the subsequences of A. There are 2^N subsequences of A.

We can’t put all the sums of subsequences into a single set since the length of the subsequence matters.

So we store the sums of subsequences into vector<unordered_set<int>> v(N + 1), where v[i] is a set of sums of subsequences of length i and v = {0}.

We try using each A[i] to update v. For each value n in v[j], we put n + A[i] into v[j + 1].

If any (n + A[i]) * N == Sum(A) * (j + 1), we can return true.

// OJ: https://leetcode.com/problems/split-array-with-same-average/

// Time: O(2^N)
// Space: O(2^N)
class Solution {
public:
bool splitArraySameAverage(vector<int>& A) {
int N = A.size(), sum = accumulate(A.begin(), A.end(), 0);
vector<unordered_set<int>> v(N + 1);
v = {0};
for (int i = 0; i < N; ++i) {
for (int j = i; j >= 0; --j) {
if (j == N - 1) continue;
for (int n : v[j]) {
int m = n + A[i];
if (m * N == sum * (j + 1)) return true;
v[j + 1].insert(m);
}
}
}
return false;
}
};


## Solution 2.

// OJ: https://leetcode.com/problems/split-array-with-same-average/

// Time: O(n^3 * M) where M the maximum possible number in A
// Space: O(n^2 * M)
// Ref: https://leetcode.com/problems/split-array-with-same-average/discuss/120667/C%2B%2B-Solution-with-explanation-early-termination-(Updated-for-new-test-case)
class Solution {
public:
bool splitArraySameAverage(vector<int>& A) {
int N = A.size(), sum = accumulate(A.begin(), A.end(), 0), M = N / 2;
bool possible = false;
for (int i = 1; i <= N && !possible; ++i) possible = sum * i % N == 0;
if (!possible) return false;
vector<unordered_set<int>> v(M + 1);
v = {0};
for (int i = 0; i < N; ++i) {
for (int j = min(M, i + 1); j >= 1; --j) {
for (int n : v[j - 1]) {
int m = n + A[i];
if (m * N == sum * j) return true;
v[j].insert(m);
}
}
}
return false;
}
};


Java

class Solution {
public boolean splitArraySameAverage(int[] A) {
if (A == null || A.length < 2)
return false;
Arrays.sort(A);
int length = A.length;
if (A[length - 1] == 0)
return true;
int gcd = A[length - 1];
for (int i = length - 2; i >= 0; i--) {
if (A[i] == 0)
break;
gcd = gcd(gcd, A[i]);
}
for (int i = length - 1; i >= 0; i--) {
if (A[i] == 0)
break;
A[i] /= gcd;
}
int sum = 0;
for (int num : A)
sum += num;
if (gcd(sum, length) == 1)
return false;
if (A[length - 2] * (length - 1) < sum - A[length - 2])
return false;
int power = 1 << length;
for (int i = 1; i < power - 1; i++) {
int curCount = 0;
int curSum = 0;
for (int j = length - 1; j >= 0; j--) {
if ((i >> j & 1) != 0) {
curCount++;
curSum += A[j];
}
}
if (sum * curCount == curSum * length)
return true;
}
return false;
}

public int gcd(int num1, int num2) {
if (num1 == 0 && num2 == 0)
return 1;
else if (num1 == 0)
return num2;
else if (num2 == 0)
return num1;
else {
while (num1 != 0 && num2 != 0) {
if (num1 > num2) {
int temp = num1;
num1 = num2;
num2 = temp;
}
num2 %= num1;
}
return num1 == 0 ? num2 : num1;
}
}
}