805. Split Array With Same Average

解法

解法一:转化成是否存在k个数使得和为target

很明显,B和C那相等的均值一定是A的均值
所以给定B的长度l,我们可以计算出B的总和应该是 s u m ( A ) l n \frac{sum(A)*l}{n}
所以问题就转化成数组里是不是有l个数的和加起来刚好等于这个值,dfs求解
但是会超时,需要剪下枝:

  1. 如果所有候选的数加起来也组不够target,pass
  2. 如果前一个数为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了
这里有两个需要注意的:

  1. x和-x不能刚好用了全部左右全部的数字,否则C会是空的
  2. 但是如果只用某一边的数字就可以凑成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)

猜你喜欢

转载自blog.csdn.net/lemonmillie/article/details/86309526