描述
最接近零的子数组和
给定一个整数数组,找到一个和最接近于零的子数组。返回第一个和最右一个指数。你的代码应该返回满足要求的子数组的起始位置和结束位置
输入:
[-3,1,1,-3,5]
输出:
[0,2]
解释: [0,2], [1,3], [1,1], [2,2], [0,4] 都可以
要求时间复杂度O(nlogn)
分析
暴力的想法是O(n^2)的方法来找出所有的组合,再判断是否接近0;
进阶一点的想法是利用前缀和,O(n)的过程可以求0,i的和sum[i],sum[j]-sum[i-1]就可以得到i-j之间的和,用dp也好其他方法也好,要求出所有的组合来,也是O(n^2);
进一步想。 O(nlogn)往往是二分或者排序,可以联想到排序。(我好恨我面试的时候为什么没想到这一点!!)
把所有的sum[i]及其下标一起排序,那么相邻的sum[i]就是接近的,只要找最接近的两个就行,两者的查所得的子数组和就是最接近0的。
代码
class Solution {
public:
/*
* @param nums: A list of integers
* @return: A list of integers includes the index of the first number and the index of the last number
*/
vector<int> subarraySumClosest(vector<int> &nums) {
vector<int>ans;
// write your code here
vector<pair<int,int> >sum;
int temp = 0;
sum.push_back(make_pair(temp,-1));
int len = nums.size();
for(int i = 0;i<len;i++){
temp += nums[i];
sum.push_back(make_pair(temp,i));
}
sort(sum.begin(),sum.end()); //按和排序
int diff = INT_MAX;
int start=0,end=0; //只有一个数的时候就返回0,0
for(int i = 1;i<len;i++){
if(abs(sum[i].first - sum[i-1].first)<=diff){
diff = abs(sum[i].first - sum[i-1].first);
start = min(sum[i].second, sum[i-1].second)+1; //注意这里 是差一个的
end = max(sum[i].second,sum[i-1].second);
}
}
ans.push_back(start);
ans.push_back(end);
return ans;
}
};