Leetcode 805. Split Array With Same Average

Problem Explanation

This problem is primarily about dividing a given integer array into two different lists, where both the lists should have the same average. If it's possible to split the original array into two lists with same average, the function should return true, otherwise false. It's also important that both lists must be non-empty (i.e., at least one element in each list).

For example, if the input array is [1,2,3,4,5,6,7,8], it can be divided into two lists [1,4,5,8] and [2,3,6,7]. Both of these lists have an average of 4.5, hence it's possible to split the original array into two lists with the same average. The function should therefore return true for this input.

Solution Approach

The solution uses dynamic programming concept to solve this problem. It first calculates the total sum of the array and then checks whether it's possible to split the array based on this sum. If it's not possible, then function will return false immediately as an early termination.

This part of the solution uses a fundamental principle that, any divisible pair can be distributed between the two lists. For example, if the sum is divisible by 3, then we can distribute the pair between the 3 lists.

The next part of the solution involves creating subsets of the products by iterating through the elements of the array and adding the sum to the respective list.

Finally, the solution checks whether the required sum (equal to the average) for each list is present in the corresponding list of sums. If we do find such a sum, then it means we can form the two lists having equal averages. Thus, we return true.

Let's visualize this with an example:

Consider the array [1,2,3,4,5,6,7,8], and we traverse all the elements in it, now let's say we are at '4' and we have the previous sums as [1,2,3], we create subsets including the current element, i.e., 4, and we get [5,6,7]. Now, we again continue this for the rest of the elements in the array. If at any point we find a sum that is equal to the required average, then our function returns true.

Python Solution

1
2python
3class Solution(object):
4  def splitArraySameAverage(self, nums):
5      """
6      :type nums: List[int]
7      :rtype: bool
8      """
9      total = sum(nums)
10      nums.sort(reverse=True)  # To reduce the time.
11      n = len(nums)
12      K = total * 1.0 / n
13      
14      # If total/n is integer, just try smaller number in A, until reach total/n
15      # Else, bfs the A, until total of A is larger than total/n
16      def subset(index, l, total):
17          if l * K == total: return True
18          if l * K < total or total + (n - l) * nums[index] < l * K: return False
19          return subset(index + 1, l + 1, total + nums[index]) or subset(index + 1, l, total)
20        
21      for l in range(1, n//2 + 1):
22          if total * l % n == 0 and subset(0, l, 0): return True
23      return False

Java Solution

1
2java
3class Solution {
4  public boolean splitArraySameAverage(int[] A) {
5      int N = A.length, S = 0, GCD = 0;
6      for (int i : A) { S += i; GCD = gcd(i, GCD); }
7      Vector<Integer> B = new Vector();
8      for (int i=0; i<N; i++) B.add(A[i] / GCD);
9      return split(B, N, S / GCD);
10  }
11  public boolean split(Vector<Integer> A, int N, int S) {
12      if (N==0) return false;
13      if (S%N==0) return true;
14      Vector<Integer> B = new Vector(A);
15      for (int i=0, n=B.size(); i<n; i++)
16          if (split(subVector(B,i), N-1, S-A.get(i))) return true;
17      return false;
18  }
19  public Vector<Integer> subVector(Vector<Integer> A3, int skp) {
20      Vector<Integer> A2 = new Vector(A3);
21      A2.remove(skp);
22      return A2;
23  }
24  public int gcd(int x, int y) {
25      return x == 0 ? y : gcd(y%x, x);
26  }
27}

JavaScript Solution

1
2javascript
3var splitArraySameAverage = function(A) {
4    const n = A.length;
5    let total = A.reduce((a, b) => a + b);
6    let intAvgFound = false;
7    for(let size = 1; size <= n/2; size++) {
8        if(total * size % n === 0) {
9            intAvgFound = true;
10            if(canFindSum(A, 0, 0, size, total * size / n)) {
11                return true;
12            }
13        }
14    }
15    return intAvgFound ? false : false;
16};
17
18let canFindSum = function(A, idx, currentSum, size, target) {
19    if(size === 0) {
20        return currentSum === target;
21    }
22    if(idx < A.length) {
23        if(canFindSum(A, idx + 1, currentSum + A[idx], size - 1, target)) {
24            return true;
25        }
26        if(canFindSum(A, idx + 1, currentSum, size, target)) {
27            return true;
28        }
29    }
30    return false;
31};

C++ Solution

1
2cpp
3class Solution {
4public:
5    bool splitArraySameAverage(vector<int>& A) {
6        int len = A.size();
7        if (len==1) return false;
8        int sum = accumulate(A.begin(), A.end(), 0);
9        sort(A.begin(), A.end());
10        for (int i=1; i<=len/2; ++i){
11            if (sum*i%len == 0 && combs(A, sum*i/len, i, len-1)) return true;
12        }
13        return false;
14    }
15private:
16    bool combs(vector<int>& A, int sum, int n, int index){
17        if (n==0) return sum==0; 
18        else if(sum<0) return false;
19        else if (sum>A[index]*n) return false;
20        for (int i=index; i>=n-1; --i){
21            if(A[i]<=sum && combs(A, sum-A[i], n-1, i-1)) return true;     
22        }
23        return false;
24    }
25};

C# Solution

1
2csharp
3public class Solution {
4    private double totalAverage;
5    public bool SplitArraySameAverage(int[] A) {
6        totalAverage = (double)A.Sum()/A.Length;
7        Array.Sort(A);
8        for(int i=1;i<=A.Length/2;i++){
9            if((A.Sum() * i) % A.Length == 0 && groupExists(A,A.Length-1,A.Sum() * i/A.Length,i)) return true;
10        }
11        return false;
12    }
13    
14    private bool groupExists(int[] A,int end,int target,int currSize){
15        if(currSize==0) return target == 0;
16        if(target<A[end]) return false;
17        for(int i=end ; i>=currSize-1;i--){
18            if(i+1<A.Length && A[i]==A[i+1]) continue;
19            if(groupExists(A,i-1,target-A[i],currSize-1)) return true;
20        }
21        return false;
22    }
23}

Conclusion

The problem of dividing an array into two subsets with an equal average may initially seem simple, but it involves a number of complex steps. It's important to understand different programming and mathematics concepts like dynamic programming, sets, and averages to solve this problem. This problem can be solved using multiple programming languages including Python, Java, JavaScript, C++, and C#.

In all these solutions, we first calculate the sum of the array and determine whether it’s divisible to form subsets. Using dynamic programming principle, the solution iteratively checks for the possibility of subsets that can form the required average. The solution validates this condition by recursively checking each subset.

If you face a similar problem, these solutions should serve as a solid reference and starting point. Practice is key to understanding them thoroughly and being able to apply the underlying principles to different but related problems.


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫