classSolution: defsplitArraySameAverage(self, nums: List[int]) -> bool: n = len(nums) if n == 1: returnFalse
s = sum(nums) for i inrange(n): nums[i] = nums[i] * n - s
m = n // 2 left = set() for i inrange(1, 1 << m): tot = sum(x for j, x inenumerate(nums[:m]) if i >> j & 1) if tot == 0: returnTrue left.add(tot)
rsum = sum(nums[m:]) for i inrange(1, 1 << (n - m)): tot = sum(x for j, x inenumerate(nums[m:]) if i >> j & 1) if tot == 0or rsum != tot and -tot in left: returnTrue returnFalse
classSolution { public: boolsplitArraySameAverage(vector<int> &nums){ int n = nums.size(), m = n / 2; if (n == 1) { returnfalse; }
int sum = accumulate(nums.begin(), nums.end(), 0); for (int &x : nums) { x = x * n - sum; }
unordered_set<int> left; for (int i = 1; i < (1 << m); i++) { int tot = 0; for (int j = 0; j < m; j++) { if (i & (1 << j)) { tot += nums[j]; } } if (tot == 0) { returntrue; } left.emplace(tot); }
int rsum = accumulate(nums.begin() + m, nums.end(), 0); for (int i = 1; i < (1 << (n - m)); i++) { int tot = 0; for (int j = m; j < n; j++) { if (i & (1 << (j - m))) { tot += nums[j]; } } if (tot == 0 || (rsum != tot && left.count(-tot))) { returntrue; } } returnfalse; } };
classSolution { publicbooleansplitArraySameAverage(int[] nums) { if (nums.length == 1) { returnfalse; } intn= nums.length, m = n / 2; intsum=0; for (int num : nums) { sum += num; } for (inti=0; i < n; i++) { nums[i] = nums[i] * n - sum; }
Set<Integer> left = newHashSet<Integer>(); for (inti=1; i < (1 << m); i++) { inttot=0; for (intj=0; j < m; j++) { if ((i & (1 << j)) != 0) { tot += nums[j]; } } if (tot == 0) { returntrue; } left.add(tot); } intrsum=0; for (inti= m; i < n; i++) { rsum += nums[i]; } for (inti=1; i < (1 << (n - m)); i++) { inttot=0; for (intj= m; j < n; j++) { if ((i & (1 << (j - m))) != 0) { tot += nums[j]; } } if (tot == 0 || (rsum != tot && left.contains(-tot))) { returntrue; } } returnfalse; } }
publicclassSolution { publicboolSplitArraySameAverage(int[] nums) { if (nums.Length == 1) { returnfalse; } int n = nums.Length, m = n / 2; int sum = 0; foreach (int num in nums) { sum += num; } for (int i = 0; i < n; i++) { nums[i] = nums[i] * n - sum; }
ISet<int> left = new HashSet<int>(); for (int i = 1; i < (1 << m); i++) { int tot = 0; for (int j = 0; j < m; j++) { if ((i & (1 << j)) != 0) { tot += nums[j]; } } if (tot == 0) { returntrue; } left.Add(tot); } int rsum = 0; for (int i = m; i < n; i++) { rsum += nums[i]; } for (int i = 1; i < (1 << (n - m)); i++) { int tot = 0; for (int j = m; j < n; j++) { if ((i & (1 << (j - m))) != 0) { tot += nums[j]; } } if (tot == 0 || (rsum != tot && left.Contains(-tot))) { returntrue; } } returnfalse; } }
boolsplitArraySameAverage(int* nums, int numsSize) { if (numsSize == 1) { returnfalse; } int n = numsSize, m = n / 2; int sum = 0; for (int i = 0; i < n; i++) { sum += nums[i]; } for (int i = 0; i < n; i++) { nums[i] = nums[i] * n - sum; } HashItem *left = NULL; for (int i = 1; i < (1 << m); i++) { int tot = 0; for (int j = 0; j < m; j++) { if (i & (1 << j)) { tot += nums[j]; } } if (tot == 0) { returntrue; } hashAddItem(&left, tot); } int rsum = 0; for (int i = m; i < n; i++) { rsum += nums[i]; } for (int i = 1; i < (1 << (n - m)); i++) { int tot = 0; for (int j = m; j < n; j++) { if (i & (1 << (j - m))) { tot += nums[j]; } } if (tot == 0 || (tot != rsum && hashFindItem(&left, -tot))) { returntrue; } } hashFree(&left); returnfalse; }
var splitArraySameAverage = function(nums) { if (nums.length === 1) { returnfalse; } const n = nums.length, m = Math.floor(n / 2); let sum = 0; for (const num of nums) { sum += num; } for (let i = 0; i < n; i++) { nums[i] = nums[i] * n - sum; }
const left = newSet(); for (let i = 1; i < (1 << m); i++) { let tot = 0; for (let j = 0; j < m; j++) { if ((i & (1 << j)) !== 0) { tot += nums[j]; } } if (tot === 0) { returntrue; } left.add(tot); } let rsum = 0; for (let i = m; i < n; i++) { rsum += nums[i]; } for (let i = 1; i < (1 << (n - m)); i++) { let tot = 0; for (let j = m; j < n; j++) { if ((i & (1 << (j - m))) != 0) { tot += nums[j]; } } if (tot === 0 || (rsum !== tot && left.has(-tot))) { returntrue; } } returnfalse; };
funcsplitArraySameAverage(nums []int)bool { n := len(nums) if n == 1 { returnfalse }
sum := 0 for _, x := range nums { sum += x } for i := range nums { nums[i] = nums[i]*n - sum }
m := n / 2 left := map[int]bool{} for i := 1; i < 1<<m; i++ { tot := 0 for j, x := range nums[:m] { if i>>j&1 > 0 { tot += x } } if tot == 0 { returntrue } left[tot] = true }
rsum := 0 for _, x := range nums[m:] { rsum += x } for i := 1; i < 1<<(n-m); i++ { tot := 0 for j, x := range nums[m:] { if i>>j&1 > 0 { tot += x } } if tot == 0 || rsum != tot && left[-tot] { returntrue } } returnfalse }
根据方法一的结论,设数组 nums 的平均数为 avg} = \dfrac{\textit{nums}}{n,我们移动了 k 个元素到数组 A 中,则此时已经数组 A 的平均数也为 avg,则此时数组 A 的元素之和为 sum}(A) = k \times \textit{avg,则该问题可以等价于在数组中取 k 个数,使得其和为 k \times \textit{avg。对应的「0-1背包问题 」则为是否可以取 k 件物品使得背包的重量为 k \times \textit{avg。我们设 dp}[i][x] 表示当前已从数组 nums 取出 i 个元素构成的和为 x 的可能性:
如果 dp}[i][x] = \text{true,表示当前已经遍历过的元素中可以取出 i 个元素构成的和为 x;
如果 dp}[i][x] = \text{false,表示当前已经遍历过的元素中不存在取出 i 个元素的和等于 x;
假设前 j - 1 个元素中存在长度为 i 的子集且子集的和为 x,则此时 dp}[i][x] = \text{true,我们当前遍历 nums}[j] 时,则可以推出一定存在长度为 i + 1 的子集且满足子集的和为 x + \textit{nums}[j],可以得到状态转移方程为: dp}[i + 1][x + \textit{nums}[j]] = dp[i][x]
根据题意可知:\dfrac{\textit{sum}(A)}{k} = \dfrac{\textit{sum}(\textit{nums})}{n,可以变换为: sum}(A) \times n = \textit{sum}(\textit{nums}) \times k,所以我们只需要找到一个元素个数为 k 的子集 A 满足上述条件即可,因此我们利用上述递推公式求出所有可能长度的子集和组合即可,此时需要的时间复杂度约为 n^2 \times \textit{sum}(\textit{nums}),按照题目给定的测试用例可能会超时,所以需要一些减枝技巧,具体的减枝技巧如下:
根据题意可以推出 sum}(A) = \dfrac{\textit{sum}(\textit{nums}) \times k}{n,则此时如果满足题目要求,则一定存在整数 k \in [1,n],使得 \big[\textit{sum}(\textit{nums}) \times k\big] \bmod n = 0,因此我们可以提前是否存在 k 满足上述要求,如果不存在则可以提前终止。
根据题目要求可以划分为两个子数组 A,B,则可以知道两个子数组中一定存在一个数组的长度小于等于 \dfrac{n}{2,因此我们只需检测数组长度小于等于 \dfrac{n}{2 的子数组中是否存在其和满足 subsum} \times n = \textit{nums} \times k 即可。
代码
[sol2-Python3]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
classSolution: defsplitArraySameAverage(self, nums: List[int]) -> bool: n = len(nums) m = n // 2 s = sum(nums) ifall(s * i % n for i inrange(1, m + 1)): returnFalse
dp = [set() for _ inrange(m + 1)] dp[0].add(0) for num in nums: for i inrange(m, 0, -1): for x in dp[i - 1]: curr = x + num if curr * n == s * i: returnTrue dp[i].add(curr) returnFalse
classSolution { public: boolsplitArraySameAverage(vector<int>& nums){ int n = nums.size(), m = n / 2; int sum = accumulate(nums.begin(), nums.end(), 0); bool isPossible = false; for (int i = 1; i <= m; i++) { if (sum * i % n == 0) { isPossible = true; break; } } if (!isPossible) { returnfalse; } vector<unordered_set<int>> dp(m + 1); dp[0].insert(0); for (int num: nums) { for (int i = m; i >= 1; i--) { for (int x: dp[i - 1]) { int curr = x + num; if (curr * n == sum * i) { returntrue; } dp[i].emplace(curr); } } } returnfalse; } };
classSolution { publicbooleansplitArraySameAverage(int[] nums) { if (nums.length == 1) { returnfalse; } intn= nums.length, m = n / 2; intsum=0; for (int num : nums) { sum += num; } booleanisPossible=false; for (inti=1; i <= m; i++) { if (sum * i % n == 0) { isPossible = true; break; } } if (!isPossible) { returnfalse; } Set<Integer>[] dp = newSet[m + 1]; for (inti=0; i <= m; i++) { dp[i] = newHashSet<Integer>(); } dp[0].add(0); for (int num : nums) { for (inti= m; i >= 1; i--) { for (int x : dp[i - 1]) { intcurr= x + num; if (curr * n == sum * i) { returntrue; } dp[i].add(curr); } } } returnfalse; } }
publicclassSolution { publicboolSplitArraySameAverage(int[] nums) { if (nums.Length == 1) { returnfalse; } int n = nums.Length, m = n / 2; int sum = 0; foreach (int num in nums) { sum += num; } bool isPossible = false; for (int i = 1; i <= m; i++) { if (sum * i % n == 0) { isPossible = true; break; } } if (!isPossible) { returnfalse; } ISet<int>[] dp = new ISet<int>[m + 1]; for (int i = 0; i <= m; i++) { dp[i] = new HashSet<int>(); } dp[0].Add(0); foreach (int num in nums) { for (int i = m; i >= 1; i--) { foreach (int x in dp[i - 1]) { int curr = x + num; if (curr * n == sum * i) { returntrue; } dp[i].Add(curr); } } } returnfalse; } }
boolsplitArraySameAverage(int* nums, int numsSize) { int n = numsSize, m = n / 2; int sum = 0; for (int i = 0; i < numsSize; i++) { sum += nums[i]; } bool isPossible = false; for (int i = 1; i <= m; i++) { if (sum * i % n == 0) { isPossible = true; break; } } if (!isPossible) { returnfalse; } HashItem *dp[m + 1]; for (int i = 0; i <= m; i++) { dp[i] = NULL; } hashAddItem(&dp[0], 0); for (int j = 0; j < numsSize; j++) { for (int i = m; i >= 1; i--) { for (HashItem *pEntry = dp[i - 1]; pEntry != NULL; pEntry = pEntry->hh.next) { int curr = pEntry->key + nums[j]; if (curr * n == sum * i) { returntrue; } hashAddItem(&dp[i], curr); } } } for (int i = 0; i <= m; i++) { hashFree(&dp[i]); } returnfalse; }
var splitArraySameAverage = function(nums) { if (nums.length === 1) { returnfalse; } const n = nums.length, m = Math.floor(n / 2); let sum = 0; for (const num of nums) { sum += num; } let isPossible = false; for (let i = 1; i <= m; i++) { if (sum * i % n === 0) { isPossible = true; break; } } if (!isPossible) { returnfalse; } const dp = newArray(m + 1).fill(0).map(() =>newSet()); dp[0].add(0); for (const num of nums) { for (let i = m; i >= 1; i--) { for (const x of dp[i - 1]) { let curr = x + num; if (curr * n === sum * i) { returntrue; } dp[i].add(curr); } } } returnfalse; };
funcsplitArraySameAverage(nums []int)bool { sum := 0 for _, x := range nums { sum += x }
n := len(nums) m := n / 2 isPossible := false for i := 1; i <= m; i++ { if sum*i%n == 0 { isPossible = true break } } if !isPossible { returnfalse }
dp := make([]map[int]bool, m+1) for i := range dp { dp[i] = map[int]bool{} } dp[0][0] = true for _, num := range nums { for i := m; i >= 1; i-- { for x := range dp[i-1] { curr := x + num if curr*n == sum*i { returntrue } dp[i][curr] = true } } } returnfalse }