• 力扣(LeetCode)805. 数组的均值分割(C++)


    状态压缩+折半搜索

    分析均值分割的性质,
    设分割后 A A A 数组长度为 k k k ,那么 B B B 数组长度为 n − k n-k nk A A A B B B 平均值相等,有 s u m A k = s u m B n − k \dfrac {sum_A}{k} = \dfrac{sum_B}{n-k} ksumA=nksumB。除法需要转换浮点数,有精度问题。为了避免精度问题,整理上式。
    整理,得 ① s u m A × ( n − k ) = s u m B × k ①sum_A\times (n-k) = sum_B\times k sumA×(nk)=sumB×k
    n u m s nums nums 所有数之和为 s u m sum sum , 有 ② s u m = s u m A + s u m B ②sum=sum_A+sum_B sum=sumA+sumB
    ① ② ①② 联立,得
    ③ s u m A × n = s u m × k ③sum_A\times n=sum\times k sumA×n=sum×k
    由于 ① < = > ③ ①<=>③ <=>问题转化为,求与 n u m num num均值相等的 A A A A A A n u m s nums nums 的子数组。原问题:求 n u m s nums nums的均值分割数组 A A A B B B

    归一化处理,令 n u m s nums nums 的每一个数 x = n x − s u m x = nx - sum x=nxsum,避免精度处理。归一化改变 n u m s nums nums 的平均值,为 0 0 0问题转化为,求均值为 0 0 0 A A A

    用状态压缩表示 A A A 选取了 n u m s nums nums 的哪些数, 1 1 1 表示选, 0 0 0 表示不选。 n u m s nums nums 最大长度 30 30 30 ,可知一共 2 30 2^{30} 230 种状态, T L E TLE TLE

    于是折半查找,把 n u m s nums nums 均分为 l e f t left left r i g h t right right 两半,对两半分别状态压缩,求均值等于 0 0 0 A A A 。设 A A A 的某状态,总和为 t o t a l total total ,如果 B B B 中存在某状态,总和为 − t o t a l -total total,两个状态之和的均值为 0 0 0 ,这也是一个可行解 。上述过程,和直接查找整个 n u m s nums nums 是等价的。但是状态数量缩减为 2 × 2 15 2\times 2^{15} 2×215

    要注意,在 r i g h t right right 中不能选取所有元素,否则相当于选择了整个 n u m s nums nums 作为 A A A 数组,不符合题意。

    代码展示
    class Solution {
    public:
        bool splitArraySameAverage(vector<int>& nums) {
            int n = nums.size(), m = n/2;//n是nums的长度,m是左子数组A的长度
            if(0==m) return false;//单元素数组//不可分割
            int sum = accumulate(nums.begin(),nums.end(),0);
            for(auto &x:nums) x = n*x - sum;//归一化//使得avg(nums) = 0//避免浮点精度
            unordered_set<int> h;//存所有状态对应的total
            for(int i = 1 ;i<(1<<m);i++){//折半搜索,先搜索left
                int total = 0;//left某状态的总和
                for(int j = 0;j<m;j++)
                    if((i>>j)&1)
                        total += nums[j];//第j位存在
                if(0 == total) return true;//状态总和为0,sumA=sum,可以分割
                h.emplace(total);
            }
            for(int i = 1;i<(1<<(n-m));i++){//再搜索right
                int total = 0;//right某状态的总和
                for(int j = 0;j<n-m;j++)
                    if((i>>j)&1)
                        total += nums[m+j];
                if(0 == total) return true;//sumB = sum
                if(i!=(1<<(n-m))-1 && h.count(-total)) return true;
            }
            return false;
        }
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    博主致语

    理解思路很重要!
    欢迎读者在评论区留言,作为日更博主,看到就会回复的。

    AC

    AC

    复杂度分析
    1. 时间复杂度: O ( n × 2 n 2 ) O(n\times 2^{\frac n 2}) O(n×22n) n n n n u m s nums nums 的长度,一共 O ( 2 × 2 n 2 ) O(2\times 2^{\frac n 2}) O(2×22n) 种状态。遍历所有状态的时间复杂度 O ( 2 n 2 ) O(2^{\frac n 2}) O(22n) ,同时遍历每个状态的所有位置的时间复杂度 O ( n ) O(n) O(n),二者是乘积关系。
    2. 空间复杂度: O ( 2 n 2 ) O(2^{\frac n 2}) O(22n) h h h 哈希集合的空间复杂度是 O ( 2 n 2 ) O(2^{\frac n 2}) O(22n) 。因为要存储 l e f t left left 中所有状态的 t o t a l total total
  • 相关阅读:
    react+vite配置module.scss(css in js)
    山东省技能兴鲁职业技能竞赛-人工智能工程技术人员
    【JS】常用正则表达式
    全栈开发学习记录:一个简单的node.js服务器以及用到的表、视图、存储过程和配套测试的前端.
    Unity Shader—04 Unity中的基础光照
    【数值分析】Jacobi、Seidel和Sor迭代法求解线性方程组(附matlab代码)
    C# 继承
    智云通CRM:越是害怕被客户拒绝,你就越会被拒绝?
    nlp之加载电商评论集
    aplus埋点笔记
  • 原文地址:https://blog.csdn.net/Innocence02/article/details/127844144