【leetcode】【2022/11/14】805. 数组的均值分割
admin
2024-01-22 11:34:40
0

问题描述:

  • 给定你一个整数数组 nums,我们要将 nums 数组中的每个元素移动到 A 数组或者 B 数组中,使得 A 数组和 B 数组不为空,并且 average(A) == average(B)
    • 如果可以完成则返回 true,否则返回 false
    • 满足 1 <= nums.length <= 30

核心思路:

  • 该题较难,考察了数学推导 + 位运算 + 折半搜索。
  • 数学推导部分如下:
    • 首先经过推导可得知,数组 A 或数组 B 的平均值原数组 nums 的平均值是相等的。
    • 因此将数组中所有数值减去 sum(nums)/n,原问题就可以转换为找到一个数组 A 其求和为 0。【其中 n 为数组长度】
    • 而直接求 nums 的平均值可能会得到浮点值影响最后结果的精度,所以在求平均值前先将 nums 中所有数值乘以数组的长度,再将所有数值减去 sum(nums),仍然可以将问题转化为找到一个数组 A 其求和为 0
    • 也就是说,对每一个数值 num 进行 num * n - sum(nums) 的预处理,最后找到 nums 中哪些数求和为 0 即可。
  • 而想要计算出所有的子集求和情况,就需要用位运算来维护元素的存取情况:
    • 因为 1 <= n <= 30,所以所有子集的存取有 2n2^{n}2n 种情况,用第 i 位用来判断数组第 i 个元素是否存入数组 A
    • 因此我们遍历 [1, 1 << n) 即遍历所有存取情况;在每一个子集中遍历数组元素,来获得当前子集求和情况。
    • 但如此计算就是暴力求解,时间复杂度为 O(2n×n)\mathcal{O}(2^n\times n)O(2n×n),当 n = 30 时自然会超时。
  • 解决的办法就是折半搜索:【该思想是本题解的主要难点】
    • 顾名思义就是搜索前半段和后半段,时间复杂度就会缩减为 O(2n2×n)\mathcal{O}(2^{\frac{n}{2}}\times n)O(22n​×n)。
    • 但此时需要进行讨论,最后子集 A 可能出现三种情况:
      1. 子集元素全部存在于数组前半段;【此时搜索前半段就可以得到某个子集求和为 0
      2. 子集元素全部存在于数组后半段;【此时搜索后半段就可以得到某个子集求和为 0
      3. 子集元素存在于前半段和后半段。
    • 情况 3 较为复杂,此时就需要用空间换时间,利用哈希表来保存前半段的所有子集和,在后半段的遍历中利用哈希表中的值即可。
    • 用哈希表来保存值时,还可能出现前半段和后半段元素同时全选的情况,此时需要避免判断该情况,具体看代码注释即可。
  • 该题的动态规划是根据 sum(nums) 的范围推导的,也就是根据值域大小来获得所有子集求和的情况,官方题解给出的动态规划解法时间复杂度为 O(n2×sum(nums))\mathcal{O}(n^2\times sum(nums))O(n2×sum(nums)),一旦求和的范围过大,动态规划解法就可能会超时。

代码实现:

  • 折半搜索解法代码实现如下:
    class Solution {
    public:bool splitArraySameAverage(vector& nums) {int n = nums.size(); // n 的取值范围为 [1, 30]if(n == 1) return false;int sum = accumulate(nums.begin(), nums.end(), 0);for(int& num : nums) num = num * n - sum; // 原本是 num = num - sum/n,但这样写会有精度问题int m = n >> 1; // 折半计算unordered_set ss;for(int i = 1; i < (1 << m); ++i) { // 二进制表示选择结果int t = 0;for(int j = 0; j < m; ++j)if(i & (1 << j)) t += nums[j]; // 求和子数组if(t == 0) return true;ss.insert(t);}for(int i = 1; i < 1 << (n-m); ++i) {int t = 0;for (int j = 0; j < (n-m); ++j)if(i & (1 << j)) t += nums[m+j];if(t == 0 or (i != (1 << (n-m))-1 and ss.count(-t))) return true;// 注意 i != (1 << (n-m))-1 表示不能“同时”左子数组全选和右子数组全选,因为同时全选就是整个数组全部选择,则必定返回 true// 左子数组全选的情况已经存在 ss 中,所以遍历右子数组之后,判断完右子数组全选不为 0 之后,就需要避免左右子数组同时全选的情况}return false;}
    };
    

参考内容:

  • 折半查找 + 二进制枚举(详解)

相关内容

热门资讯

这场陆家嘴论坛,把中国经济金融... 来源:市场资讯 (来源:券研社) 从2008年启航,陆家嘴论坛就是观察中国经济金融走势的重要风向标...
原创 6... 周末去看房的人,情绪比以前复杂得多。售楼处里灯光还是亮,样板间还是精致,销售的话术却变了。前些年最常...
监管批复!陶曦就任成都银行行长... 2026年6月23日,根据国家金融监督管理总局消息,《成都银行股份有限公司关于陶曦高级管理人员任职资...
港股AI双雄遭空头伏击 7月超... 财联社6月23日讯(编辑 胡家荣)港股AI大模型板块的两大领头羊——智谱(02513.HK)与MIN...
山西运城:高度重视,已组成联合... “盐湖公安”微信公号、浪潮新闻 6月23日,山西省运城市公安局盐湖分局发布警情通报: 近日,网络平台...
监管批复!向云勇就任湖南吉首农... 2026年6月23日,根据国家金融监督管理总局消息,《湖南吉首农村商业银行股份有限公司关于对向云勇同...
曹操出行(2643.HK)Ro... 过去几年,大模型让AI完成了从“会聊天”到“会思考”的跨越。随着模型能力不断提升,产业关注点也开始从...
原创 金... 2026年6月23日,金价处在回调震荡阶段,水贝足金首饰批发价挂到1076元每克,但周大福、周生生那...
字节跳动CEO梁汝波:收缩业务... 在6月23日举行的火山引擎Force大会上,字节跳动CEO梁汝波表示,AI的影响力至少不亚于PC、W...
香港黄金交易平台第一梯队有哪些... 香港一直是亚洲重要的黄金交易中心。很多人在选择黄金交易平台时,面对大量的品牌,难免会感到困惑。香港黄...
WAVES 2026:今年盛夏... 盛夏赴约WAVES 2026!一群迎风的少数人,掀起中国新一代创新力量的风口。 2026年,创投圈的...
高鑫零售,试水“第三条路” 6月18日,盐城首家M会员商店轻享店在江苏盐南高新区佳源广场试营业。这是大润发母公司高鑫零售旗下全国...
28家企业排队,美妆IPO迎来... 沉寂三年后,美妆IPO重新热了起来。 2020年至2021年,是中国美妆企业上市的“黄金窗口”。贝泰...
原创 套... #格力第一大股东套现近 15.9 亿 #,格力电器正式发布减持结果公告,公司第一大股东珠海明骏(高瓴...
原创 昆... 6月23日,昆仑行机器人宣布,公司自2026年3月注册成立不足90天内,接连完成三轮融资,累计规模达...
心智观察所:从磷化铟的故事看中... 【文/观察者网 心智观察所 】 云南锗业的股价在2026年4月跑出了一波让人困惑的行情。 这家以锗为...
马云带着一群阿里合伙人,下田插... “马云带着一群阿里合伙人下田插秧,此次插秧团建的“同事们”阵容强大,吴泳铭、邵晓锋、蒋凡、吴泽明、蒋...
胖东来近半年累计销售额超139... 上证报中国证券网讯 6月22日晚,胖东来创始人于东来通过社交平台分享了集团近半年的经营情况。数据显示...
原创 帮... 达沃斯开幕+长川/卫星中报开门红:今天A股走“业绩提纯”,别蹭概念刀口舔血 老铁们,今天的早观察关键...
原创 腾... 原创首发 | 金角财经(ID: F-Jinjiao) 作者 | 田羽 “中国AMD”准备登陆A股了。...