• 力扣每日一题:805. 数组的均值分割【折半查找+二进制枚举】


    给定你一个整数数组 nums

    我们要将 nums 数组中的每个元素移动到 A 数组 或者 B 数组中,使得 A 数组和 B 数组不为空,并且 average(A) == average(B) 。

    如果可以完成则返回true , 否则返回 false  。

    注意:对于数组 arr ,  average(arr) 是 arr 的所有元素的和除以 arr 长度。

    示例 1:

    输入: nums = [1,2,3,4,5,6,7,8]
    输出: true
    解释: 我们可以将数组分割为 [1,4,5,8] 和 [2,3,6,7], 他们的平均值都是4.5。
    

    示例 2:

    输入: nums = [3,1]
    输出: false
    

    提示:

    • 1 <= nums.length <= 30
    • 0 <= nums[i] <= 104

    分析:这道题目我们先设几个未知数,a 代表A数组的长度,suma 代表A数组的和,b代表数组B的长度。sumb代表数组B的和,然后我们就可以列出方程

    /**
     *          a+b = n ;
     *         suma+sumb =sum ;
     *         suma/a =sumb/b ;
     *         suma = a*sumb/b;
     *         a*sumb/b + sumb =sum ;
     *         n*sumb/b = sum
     *         n*sumb = b*sum ;
     *
     *         sumb = b*sum / n ;
     *         sumb/b = sum / n  ;
     *
     */

    可以看到的是 数组B的平均值等于原数组的平均值。如果我们不对原数组进行数据处理的话,我们每次枚举出的组合都要求平均值,我们就可以直接让原数组的每个元素都减去数组的平均值,

    题目就转化为:在数组 numsnumsnums 中找出一个子数组 A,使得其和为 0。

    数组 nums 的长度范围为 [1,30][1, 30][1,30],如果我们使用暴力枚举子数组的方法,时间复杂度为 O(2^n)),会超时。我们可以使用折半查找的方法,将时间复杂度降低到 O(2^{n/2})

    我们将数组 nums 分成左右两部分,那么子数组 AAA 可能存在三种情况:

    子数组 AAA 完全在数组 nums 的左半部分;
    子数组 AAA 完全在数组 nums 的右半部分;
    子数组 AAA 一部分在数组 nums 的左半部分,一部分在数组 nums 的右半部分。


    我们可以使用二进制枚举的方法,先枚举左半部分所有子数组的和,如果存在一个子数组和为 0,直接返回 true,否则我们将其存入哈希表 left 中;然后枚举右半部分所有子数组的和,如果存在一个子数组和为 0,直接返回 true,否则我们判断此时哈希表 vis 中是否存在该和的相反数,如果存在,直接返回 true。

    需要注意的是,我们不能同时全选左半部分和右半部分,因为这样会导致子数组 B 为空,这是不符合题意的。在实现上,我们只需要考虑数组的 n−1 个数。

    废话不多说直接上代码:

    AC代码:

    1. class Solution {
    2. public boolean splitArraySameAverage(int[] nums) {
    3. if(nums.length==1){
    4. return false ;
    5. }
    6. int n = nums.length;
    7. int m = n /2 ;
    8. int sum = 0 ;
    9. for (int num : nums) {
    10. sum += num ;
    11. }
    12. for (int i =0 ;i
    13. nums[i] = nums[i] * n - sum ;
    14. }
    15. Set left = new HashSet<>() ;
    16. for(int i =1 ;i<(1<
    17. int tot = 0 ;
    18. for (int j = 0 ;j
    19. if ((i&(1<0){
    20. tot += nums[j] ;
    21. }
    22. }
    23. if (tot==0){
    24. return true ;
    25. }
    26. left.add(tot) ;
    27. }
    28. int rsum = 0 ;
    29. for(int i = m ;i
    30. rsum += nums[i] ;
    31. }
    32. for (int i =1 ;i<(1<<(n-m));i++){
    33. int tot =0 ;
    34. for (int j = m ;j
    35. if ((i& (1<<(j-m)))!=0){
    36. tot += nums[j] ;
    37. }
    38. }
    39. if (tot ==0|| (rsum!=tot && left.contains(-tot) )){
    40. return true ;
    41. }
    42. }
    43. return false ;
    44. }
    45. }

  • 相关阅读:
    Java抽象类和接口
    某赛驱动器调节工具DM-Series使用笔记
    angular:简单实现图片如果超过屏幕高度则滚动置顶;没超过则水平垂直居中
    获取Greenplum 的元数据信息,schema下面的表和列信息
    SpringBoot项目创建方式一:Spring Initializr(Web界面方式)
    智能导览与实时监测:数字孪生助力景区管理
    【Python 常用脚本及命令系列 12.1 -- OpenCV 设置图片区域为某个颜色】
    【毕业设计】基于单片机的太空游戏机 - 嵌入式 物联网 stm32 51
    一线大厂研发流程
    java基础之内部类
  • 原文地址:https://blog.csdn.net/weixin_54046648/article/details/127848137