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

参考内容:

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

相关内容

热门资讯

多措并举提高上市公司质量 促进... 来源:证券日报 “促进投融资功能协调,必须牢牢抓住提高上市公司质量这个关键。”1月11日,证监会副主...
容百科技:与宁德时代“1200... 1月15日晚,容百科技发布关于再次延期回复上海证券交易所《问询函》暨公司股票继续停牌的公告。 上证...
海富通瑞福债券型证券投资基金解... 1月15日,海富通基金管理有限公司发布公告称,依据《公开募集证券投资基金信息披露管理办法》、《基金管...
A股有“钱”景 07 AI红利转移应用端 08 指数攀高何处登顶?
国资收入能否“跳一跳”,闵行消... “区属国资委收入已经连续两年6600万元,今年能否实现奋力一跳?”“在促进消费方面,政府能做什么?”...
央行下调再贷款利率 增加再贷款... 下调各类结构性货币政策工具利率、增加支农支小再贷款额度、设立民营企业再贷款、拓展多个结构性货币政策工...
央行副行长邹澜:继续综合施策 ... 中国网财经1月15日讯 今日,国务院新闻办公室举行新闻发布会,介绍货币金融政策支持实体经济高质量发展...
山东多城市消费上新,品质生活触... 海报新闻记者 李金珊 实习生 宋亚轩 孙晔 报道 上午十点,临沂兰山区的李女士送完孩子回家,指尖轻点...
“20cm”六连板,大牛股明日... 1月15日晚,志特新材(300986)、*ST铖昌(001270)两只停牌核查股同日宣布,即将复牌。...
原创 特... 特朗普政府试图将委内瑞拉的石油资源纳入美国巨头的囊中,但事与愿违。这场旨在促成巨额投资的白宫会议,最...
原创 谢... 谢尔盖·布林:科技巨擘的崛起与慈善之路 2026年1月12日,一个值得铭记的日子。这一天,在Alph...
马士基宣布恢复红海航线 航运业... 财联社1月16日讯(编辑 牛占林)丹麦航运巨头马士基(Maersk)当地时间周四表示,在该地区安全形...
贵金属价格上涨能否持续 回顾2025年大类资产表现,以黄金、白银、铂族金属为代表的贵金属板块价格一路狂飙,令全球投资者印象深...
手握金条无处安放?银行保管箱“... 本报(chinatimes.net.cn)记者付乐 见习记者 林佳茹 北京报道 “现在网点暂时没有空...
雷军直播再谈“反小字营销”!新... 1月15日晚,小米创办人、董事长兼CEO雷军在直播中再度聚焦“小字营销”问题,明确表达小米反对该行业...
重庆今年首只新股至信股份上市 ... 1月15日,重庆至信实业股份有限公司(以下简称“至信股份”)在上海证券交易所主板敲锣上市,成为今年A...
创历史新高!2025年我国外汇... 国家外汇管理局1月15日发布数据显示,2025年,我国外汇市场交易量达42.6万亿美元,企业外汇套期...
跨境电商运营:2026全球瑜伽... 今天分享的是:跨境电商运营:2026全球瑜伽服市场洞察报告 报告共计:41页 《2026全球瑜伽服市...
中文在线涨势“刹车”,上市以来... 来源:市场资讯 来源:国际金融报 1月15日,连续多日因“狂飙”行情被称为新“易中天”之一的中文在线...
原创 1... 写在文章前的声明:在本文之前的说明:本文中所列的投资信息,只是一个对基金资产净值进行排行的客观描述,...