解题思路
看完题面,就知道咱们至少要遍历一遍所给数组,且在遍历的同时求出左数组元素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每次遍历的同时,j和k也会遍历一遍数组,因此时间复杂度达到了O(n^2),要是通过了自然对不起这题的medium难度了。
通过分析,i的这一次遍历是绕不过的,那我们只好从求数组中元素个数这里下手减少时间复杂度咯。
这时候,我们就可以使用前缀和数组来实现这个过程,它在求数组中前缀和的值的时候仅有O(1)的时间复杂度,很好地满足了我们的要求。
但很明显,本题并不是简单地求前缀和就完事了,它需要知道0和1的个数,对于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),达到了题目要求。