设nums数组的平均数为avg=nums/n,我们移动k个元素到数组A中,则此时数组A的平均数也为avg,sum(A)=k*avg
该问题等价为从数组中选出k个数,使得k个数之和为k*avg,即转化为0-1背包问题(从书包里取k件物品,使得背包重量为k*avg)
but!如果直接利用递推公式求解时间会超限,因此需要一些剪枝技巧
class Solution {
public boolean splitArraySameAverage(int[] nums) {
int n=nums.length,m=n/2;
if(n==1)
return false;
//计算sum
int sum=0;
for(int num:nums)
sum+=num;
//剪枝
boolean possible=false;
for(int i=1;i<=n;i++){
if(sum*i%n==0){
possible=true;
break;
}
}
//数组A不存在,可以提前终止
if(!possible)
return false;
//初始化dp
Set<Integer>[] dp=new Set[m+1];
for(int i=0;i<=m;i++)
dp[i]=new HashSet<>();//dp存每种长度的子集和
dp[0].add(0);
//计算dp
for(int num:nums){
for(int i=m;i>=1;i--){//k
for(int x:dp[i-1]){//i-1个元素的sum
int curr=x+num;//当前i个元素的sum(A)
if(curr*n==sum*i)//存在满足条件的A
return true;
dp[i].add(curr);//sum(A)加进dp[i]
}
}
}
return false;
}
}
时间复杂度: O ( n 2 ∗ s u m ( n u m s ) ) O(n^2*sum(nums)) O(n2∗sum(nums))
空间复杂度: O ( n ∗ s u m ( n u m s ) ) O(n*sum(nums)) O(n∗sum(nums)),一共有 n 种长度的子集,每种长度的子集和最多有 sum(nums) 个。