本文主要是对官方题解的个人理解, 旨在学习
如果对你有用的话, 麻烦点个赞, 感激不尽
一. 问题描述
二. 问题分析
三. 关键点
四. 代码实现及解释
1. 力扣链接: 力扣805:数组的均值分割
2. 问题描述: 给定数组nums, 长度1到30, 里面元素是0到10000的整数, 要求把数组分成两组A和B, 并且这两组的平均数相等
1. 分成两组, 每一个数据可能在A组, 也可能在B组, 每个数字有两种分发, 那30个数字就有种分法, 粗暴的做法就是每种可能都遍历一遍, 但是会执行超时. 通过将数组分为前后两段, 分别遍历, 那就变成了.
2. 根据题意, 分组后的平均值相同, 这样的话, 平均值其实就是整个nums的平均值, 因此可以把每一个元素都减去平均值, 就会得到一个均值是零的数据组, 这时, 只要找到某个元素的集合的总和是0, 那就是可以完成分组(当然不能能把所有元素都取完, 要给B组留个种子才行).
减去平均值的做法比较巧妙了, 但是官方解答也提示了, 可能引入浮点数的问题, 可通过先将数组中数据都乘以数组长度来解决.
3. 将减掉均值的新数组分成两段, 遍历前半段, 并记录每一种取法的总和A1; 然后在遍历后半段时, 就可以将后半段种每一的选取结果进行求和得到B1, 如果-B1在前半段计算的结果集合里, 那就是判断可以完成分组.
如何实现分组: 即种选取方案怎么通过代码实现, 可以通过二进制枚举的方式实现.
比如前半段数组长度是2, 那就是4种可能的选取方式, 那就遍历数字1到3(range(1,)4).
遍历1到3, 只有三种选取结果呀, 不对呀, 被忘了其中一种吧? 其实有一种是所有的元素都不选, 是不合格的, 因为一个都不选, 那就是元素和是0, 这种情况会影响集合有数据时, 和为0的情况, 所以不遍历数字0, 从1开始
数字1时:
1). 将数字1进行位运算, 右移0位, 然后和1做与运算 得到结果1, 表示选中第一个元素
2). 将数字1进行位运算, 右移1位, 然后和1做与运算 得到结果0, 表示未选中第二个元素
此时一种选取方式就完成了
数字2时:
1). 将数字2进行位运算, 右移0位, 然后和1做与运算 得到结果0, 表示未选中第一个元素
2). 将数字2进行位运算, 右移1位, 然后和1做与运算 得到结果1, 表示选中第二个元素
此时另一种选取方式就完成了
数字3时:
1). 将数字3进行位运算, 右移0位, 然后和1做与运算 得到结果1, 表示选中第一个元素
2). 将数字3进行位运算, 右移1位, 然后和1做与运算 得到结果1, 表示选中第二个元素
此时另一种选取方式就完成了
class Solution:
def splitArraySameAverage(self, nums: List[int]) -> bool:
n = len(nums)
if n == 1:
return False
s = sum(nums)
for i in range(n): # 处理数据, 元素统一乘以n, 减去平均数. 因为元素都扩大了n倍, 所以平均值也扩大了n倍, 减去s就是减去平均值的n倍
nums[i] = nums[i] * n - s
m = n // 2 # 一半 取整, 避免n是奇数时, m不是整数的问题
left = set()
for i in range(1, 1 << m): # 1做位运算, 向右移动m位, 其实就是变成了2的m次方, 就是取法的总数
tot = sum(x for j, x in enumerate(nums[:m]) if i >> j & 1)
# 上面的方法就是三中提到的核心点的写法, 数字向左移动0位, 1位等等的操作, 每一种取数方法的演绎
if tot == 0:
# 有零存在, 就说明可以实现分组了, 可提前结束
return True
left.add(tot)
rsum = sum(nums[m:])
for i in range(1, 1 << (n - m)): # 后半段的遍历
tot = sum(x for j, x in enumerate(nums[m:]) if i >> j & 1)
if tot == 0 or rsum != tot and -tot in left:
# 当rsum == tot时, 说明是后半段的所有数都取到了, 那-tot in left就一定会满足, 此时是不符合要求的, 因为前半段中有一种情况是前半段全部都取了, 后半段如果也全部都取, 那就变成只分一组了, 因此要求rsum != tot
return True
return False
作者:力扣官方题解
链接:https://leetcode.cn/problems/split-array-with-same-average/solutions/1966163/shu-zu-de-jun-zhi-fen-ge-by-leetcode-sol-f630/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。