【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;}
    };
    

参考内容:

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

相关内容

热门资讯

原创 4... 写在文章前的声明:在本文之前的说明:本文中所列的投资信息,只是一个对基金资产净值进行排行的客观描述,...
胜宏科技港股大涨49% 做完英... 记者 陈月芹 4月21日,全球AI算力板龙头胜宏科技(02476.HK)登陆港交所,上市首日股价大涨...
永赢基金:聚焦“科技新锐”,科... 数据来源:Wind,时间统计区间为2025/1/1-2026/4/21,指数过往表现不预示未来,不构...
五大阅读趋势显现!当当网发布2... 在第31个世界读书日即将来临之际及首个全民阅读活动周期间,当当网正式发布2026国民阅读洞察报告。 ...
业绩逐季回暖 老百姓大药房一季... 上证报中国证券网讯(记者 夏子航)4月22日晚,老百姓大药房发布2025年年报和2026年一季报。今...
中国20强城市大洗牌:苏州接近... 中国的城市经济竞争格局一直在变化,每年发布的GDP数据都会对城市经济实力进行重新排列。2025年榜又...
直击金宏气体股东会:预期年内氦... 《科创板日报》4月22日讯(记者 郭辉)金宏气体日前举行2025年度股东大会。会上该公司审议了公司年...
5月1日起,俄据悉将叫停哈萨克... 据行业消息人士透露,俄罗斯将于5月1日起停止经友谊管道转运哈萨克斯坦输往德国的石油,相关调整计划已送...
深化具身智能生态布局 京东携手... 4 月 22 日,京东与国内消费级人形机器人头部企业松延动力正式达成三年期战略合作。双方将围绕产品研...
原创 帮... 先问你一个问题,美伊停火今晚到期,按常理避险情绪该升温,黄金应该涨吧?结果恰恰相反——原油涨了,黄金...
300295、600889,将... 三六五网、南京化纤,将被*ST。 公司股票自4月23日开市起停牌一天,于4月24日开市起复牌并实施退...
能源大变天!外媒:羡慕中国的石... 这一次油价突破 110 美元的能源危机,着实魔幻。如果放在十年前,没人会相信中国能在这场风波中获利,...
黄金涨跌两难,现在还能上车吗? 中新网4月22日电(记者 左雨晴) 四月以来,美伊局势反复拉扯,美联储降息预期一变再变。黄金价格在4...
“我身体健康”,库克现身员工大... 当地时间4月21日,受苹果官宣CEO换届影响,公司股价盘中下探超2%,总市值失守4万亿美元关口,收盘...
库克留下一个悬念 工程师能否拯救创新节奏? 听筒Tech(ID:tingtongtech)原创 文 | 赵 森 ...
探索消费信贷与社交支付深度融合... 腾讯这一金融产品再添新功能,4月19日,北京商报记者注意到,微信分付灰度测试转账功能引发热议,在向微...
土耳其主要银行股指早盘下跌2% 每经AI快讯,4月20日,土耳其主要银行股指早盘下跌2%。 每日经济新闻
好用的OTA代运营源头厂家 在如今竞争激烈的酒旅行业中,OTA代运营服务成为了众多酒店、民宿提升竞争力的关键。但市场上的代运营厂...
成都五一出游全国热门第三 “五一”假期临近,同程旅行最新发布的《2026“五一”旅行趋势报告》显示,今年“五一”期间成都同时位...