lc 805. Split Array With Same Average
https://leetcode.com/problems/split-array-with-same-average/
一个数组,能否分成两部分,使之平均值相同。解题过程很愉快呀。
经过几次转换,变成一个比较简单的题目。
问题1:原始数组a,分成两个子数组a1,a2。a1和a2的均值相同,则必须等于数组整体均值ave。就是找有没有非空真子集的均值和ave相同。
问题2:整体数组都减去均值,得到新数组a_new,于是就是找a_new中有没有非空真子集的和为0。先检测如果有0值,直接返回True。
问题3:如果这个数组子集和为0,那么有正有负,他们加和为0。我们把a_new根据正负分成两部分,a_p和a_n。那么就是说,a_p中有非空真子集的和加上a_n中某个非空真子集的和为0。
问题4:a_n中的负数都取绝对值。问题转化为:对于两个集合a_p和a_n,是否能各取一个非空真子集,是两个子集的和相同?能返回True,不能则false。
到了问题4,相信已经很简单了,就算不是简单,也是再也不能转化成更简单的描述方式了,剩下的就是怎么用算法搞定它了。
使用两个set,分别记录a_p和a_n的所有子集的和出现的所有可能就行了。时间空间复杂度都是2^n,指数级别的,求问有没有办法可以避免?
a_p_set=set()
for n in a_p:
for inset in list(a_p_set):
bb.add(inset + n)
bb.add(n)
然后两个set都扔掉最大的那个和(因为真子集,不能包含所有)。然后看有没有交集,有就True,没有就false。
哈哈哈哈哈哈哈,是不是很简单??!
我一提交结果,啪啪啪打脸,直接wa了。
原来是因为float两个set,数学上求和相同的两堆数字用float表示下,求和并不同。怎么办?牺牲一定精度??万一牺牲的精度正好把本来就不同的数字当作同一个怎么办????
zing~想到了。float是我们在求平均数的时候引入的。那么这个float乘以数组长度必然是一个整数,我们在求均值前,先把数组各个数都乘以数组长度,不就都是整数了嘛!
长代码,a了:
注意有一些边界的坑,比如只有一个数,等等
class Solution: def splitArraySameAverage(self, A): """ :type A: List[int] :rtype: bool """ l=len(A) if l<=1: return False A=[a*l for a in A] s=sum(A) ave=s/l for i in A: if ave==float(i): return True a=[i-ave for i in A] b=[] c=[] for i in a: if i<0: c.append(-i) else: b.append(i) bb=set() cc=set() for n in b: for inset in list(bb): bb.add(inset + n) bb.add(n) for n in c: for inset in list(cc): cc.add(inset + n) cc.add(n) sb=sum(b) sc=sum(c) bb.remove(sb) cc.remove(sc) if len(bb.intersection(cc))>=1: return True return False