Split Array With Same Average
HardPrompt
You are given an integer array nums.
You should move each element of nums into one of the two arrays A and B such that A and B are non-empty, and average(A) == average(B).
Return true if it is possible to achieve that and false otherwise.
Note that for an array arr, average(arr) is the sum of all the elements of arr over the length of arr.
Example 1:
Input: nums = [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 an average of 4.5.Example 2:
Input: nums = [3,1]
Output: false
Constraints:
1 <= nums.length <= 300 <= nums[i] <= 104
Approaches
2 approaches with complexity analysis and trade-offs.
This is a straightforward approach that checks every possible partition of the array. We can use recursion to generate all subsets of nums to form the first array A. For each generated subset A, we check if it's a valid candidate (non-empty and not the full array). If it is, we calculate its average and the average of the remaining elements (forming array B). If the averages are equal, we've found a solution.
Algorithm
- The core idea is to check for each possible subset
Aifavg(A) == avg(nums). The conditionavg(A) == avg(B)simplifies toavg(A) == avg(nums). - This can be written as
sum(A) / len(A) == totalSum / N, orsum(A) * N == totalSum * len(A). - We can iterate through all possible lengths
kfor subsetAfrom1toN-1. - For each
k, we need to find if there's a subset of sizekwith a sum equal to(totalSum * k) / N. - A recursive helper function
find(index, k, targetSum)can be used to solve this subset sum problem. - The function explores two paths at each element
nums[index]: either include it in the subset or not. - The recursion stops when a subset of size
kis formed or when all elements are processed.
Walkthrough
The problem asks if we can partition nums into two non-empty arrays A and B with equal averages. This condition sum(A)/len(A) == sum(B)/len(B) is equivalent to sum(A)/len(A) == totalSum/N, where totalSum and N are the sum and length of the original array nums. This simplifies to sum(A) * N == totalSum * len(A).
This transforms the problem into a search for a non-empty proper subset A that satisfies this equation. The brute-force approach is to generate all possible subsets of nums, and for each subset, check if it satisfies the condition. We can implement this using a backtracking algorithm. We iterate through all possible lengths k for the subset A (from 1 to N/2) and for each k, we check if a subset of this size exists with the required sum (totalSum * k) / N. The check is done via a recursive function that explores including or excluding each element from the subset.
class Solution { public boolean splitArraySameAverage(int[] nums) { int n = nums.length; if (n < 2) { return false; } int totalSum = 0; for (int num : nums) { totalSum += num; } for (int k = 1; k <= n / 2; k++) { if ((totalSum * k) % n == 0) { int targetSum = (totalSum * k) / n; if (canFindSum(nums, 0, k, targetSum)) { return true; } } } return false; } private boolean canFindSum(int[] nums, int index, int k, int targetSum) { if (k == 0) { return targetSum == 0; } if (index >= nums.length || k < 0 || targetSum < 0) { return false; } // Option 1: Include nums[index] in the subset if (canFindSum(nums, index + 1, k - 1, targetSum - nums[index])) { return true; } // Option 2: Exclude nums[index] from the subset if (canFindSum(nums, index + 1, k, targetSum)) { return true; } return false; }}Complexity
Time
O(N * 2^N). The recursive function `canFindSum` explores `2^N` paths in the worst case. This function is called in a loop that runs up to `N/2` times.
Space
O(N), where N is the number of elements in `nums`. This is for the recursion stack depth.
Trade-offs
Pros
Simple to understand and implement.
It's a good starting point for thinking about the problem.
Cons
Highly inefficient due to its exponential time complexity.
Will result in a 'Time Limit Exceeded' (TLE) error on platforms like LeetCode for the given constraints.
Solutions
Solution
class Solution {public boolean splitArraySameAverage(int[] nums) { int n = nums.length; if (n == 1) { return false; } int s = Arrays.stream(nums).sum(); for (int i = 0; i < n; ++i) { nums[i] = nums[i] * n - s; } int m = n >> 1; Set<Integer> vis = new HashSet<>(); for (int i = 1; i < 1 << m; ++i) { int t = 0; for (int j = 0; j < m; ++j) { if (((i >> j) & 1) == 1) { t += nums[j]; } } if (t == 0) { return true; } vis.add(t); } for (int i = 1; i < 1 << (n - m); ++i) { int t = 0; for (int j = 0; j < (n - m); ++j) { if (((i >> j) & 1) == 1) { t += nums[m + j]; } } if (t == 0 || (i != (1 << (n - m)) - 1) && vis.contains(-t)) { return true; } } return false; }}Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.