解法
解法一:转化成是否存在k个数使得和为target
很明显,B和C那相等的均值一定是A的均值
所以给定B的长度l,我们可以计算出B的总和应该是
所以问题就转化成数组里是不是有l个数的和加起来刚好等于这个值,dfs求解
但是会超时,需要剪下枝:
- 如果所有候选的数加起来也组不够target,pass
- 如果前一个数为a,它失败了,这个数也是a,那也不用遍历【瞬间快了】
class Solution(object):
def splitArraySameAverage(self, A):
"""
:type A: List[int]
:rtype: bool
"""
A.sort()
n = len(A)
total = sum(A)
P = [0] * n
P[0] = A[0]
for i, a in itertools.islice(enumerate(A), 1, None):
P[i] = P[i - 1] + a
def check(i, l, target):
if i == -1:
return l == 0 and target == 0
if l == 0:
return target == 0
if target < 0:
return False
if target > P[i]:
return False
for j in xrange(i, l - 2, -1):
if (j==i or A[j]!=A[j+1]) and check(j - 1, l - 1, target - A[j]):
return True
return False
for l in xrange(1, n // 2 + 1):
if total * l % n == 0 and check(n - 1, l, total * l / n):
return True
return False
解法二:中间相遇
我觉得大概这种和刚好等于多少多少的类型都可以用中间相遇来解
但是由于B的均值是确定的,但是和不一定,如何得到B的固定的和呢?
我们把A里的每个数都减去平均值aver
,那么A的均值就变成了0,B的均值也是0,和就也固定为0了
使用中间相遇法,把数组分成左右两部分,如果左边有和为x
并且右边为-x
,那么把两部分的数组拿起来就可以拼成B了
这里有两个需要注意的:
- x和-x不能刚好用了全部左右全部的数字,否则C会是空的
- 但是如果只用某一边的数字就可以凑成0了,那么就不用再考虑后面的了
class Solution(object):
def splitArraySameAverage(self, A):
"""
:type A: List[int]
:rtype: bool
"""
from fractions import Fraction
n = len(A)
total = sum(A)
A = [a-Fraction(total,n) for a in A]
if n==1:
return False
AL = A[:n//2]
AR = A[n//2:]
def all_sums(lis):
res = set()
for a in lis:
new = set()
new.add(a)
for num in res:
new.add(num+a)
res |= new
return res
left = all_sums(AL)
if 0 in left:
return True
right = all_sums(AR)
if 0 in right:
return True
sum_left = sum(AL)
sum_right = sum(AR)
return any(-x in right and (x,-x)!=(sum_left,sum_right) for x in left)