菜狗题解:前缀和(C++)——力扣第278场周赛第二题

1,293 阅读2分钟

原题链接5981. 分组得分最高的所有下标

解题思路

看完题面,就知道咱们至少要遍历一遍所给数组,且在遍历的同时求出左数组元素0的个数和右数组元素1的个数。 那么如何求出左右数组中0和1的个数的,最容易想到的自然是暴力遍历求一遍咯,那么,我们可以写出以下代码:

暴力做法

class Solution {
public:
    vector<int> maxScoreIndices(vector<int>& nums) {
        vector<int> ans;
        int n = nums.size();
        
        int sumleft = 0, sumright = 0, sum = 0, max = sum;
        for (int i = 0; i <= n; i++) 
        {
            sumleft = 0, sumright = 0;
            for(int j = 0; j < i; j++)
            {
                if(nums[j] == 0) sumleft ++;
            }
            for(int k = i; k < n; k++)
            {
                if(nums[k] == 1) sumright ++;              
            }
            sum = sumleft + sumright;   
            
            if (sum > max) 
            {
                max = sum;
                ans.clear();
                ans.push_back(i);
            }
            else if (sum == max) ans.push_back(i);
        }
        
        return ans;
    }
};

果不其然,这样的暴力做法华丽丽地TLE了,分析一下不难发现,在i每次遍历的同时,jk也会遍历一遍数组,因此时间复杂度达到了O(n^2),要是通过了自然对不起这题的medium难度了。

通过分析,i的这一次遍历是绕不过的,那我们只好从求数组中元素个数这里下手减少时间复杂度咯。 这时候,我们就可以使用前缀和数组来实现这个过程,它在求数组中前缀和的值的时候仅有O(1)的时间复杂度,很好地满足了我们的要求。 但很明显,本题并不是简单地求前缀和就完事了,它需要知道01的个数,对于1,我们可以就当作简单的前缀和来求取就好,毕竟前缀和数组中的值自然地代表了从头到尾1的个数,那么对于0,其实也只需要用当前i的值(当前左边数组的元素个数)减去左边数组中1的个数即可。

这些都完成后,咱们还没有完全达到题目要求哦。题目并不是简单要我们给出最高得分,而是需要给出最高得分的所有不同下标。 这个时候,我们可以使用一个vector数组ans来方便地解决:定义一个max值,并不断将其与i每次遍历求出来的sum值进行比较: 假如sum == max,我们就把当前i的值压入ans数组中; 假如sum > max,我们就把ans数组中的值全部清空,再把当前i的值压入ans数组中即可,当然,别忘了让max = sum。 最终代码如下:

最终代码

class Solution {
public:
    vector<int> maxScoreIndices(vector<int>& nums) {
        int s[100010];
        vector<int> ans;
        int n = nums.size();
        
        s[0] = nums[0];
        for (int i = 1; i < n; i ++ ) s[i] = s[i - 1] + nums[i];//构建前缀和数组
        
        int sumleft = 0, sumright = 0, sum = 0, max = sum;
        for (int i = 0; i <= n; i++) 
        {
            if(i == 0) ans = s[n - 1];
            else
            {
                sumleft = i - s[i - 1];
                sumright = s[n - 1] - s[i - 1];
                sum = sumleft + sumright;   
            }//计算每次i不同时的得分

            if (sum > max) 
            {
                max = sum;
                ans.clear();
                ans.push_back(i);
            }
            else if (sum == max) ans.push_back(i);//维护答案数组ans
        }

        return ans;
    }
};

时间复杂度

由于前缀和数组求数组中前缀和的值的时候仅有O(1)的时间复杂度,因此最终代码的时间复杂度就是O(n),达到了题目要求。

278-2.png