您的位置:首页 > 其它

LeetCode 53. Maximum Subarray

2017-03-14 20:05 281 查看

LeetCode 53. Maximum Subarray

Description

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

For example, given the array
[-2,1,-3,4,-1,2,1,-5,4]
,

the contiguous subarray
[4,-1,2,1]
has the largest sum =
6
.

暴力枚举,时间复杂度 O(n3)

// 伪代码
for i ← 1 to n
for j ← i to n
sum ← a[i]+..+a[j]
ans ← max(ans, sum)


class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
int ans = -2147483647;
for (int st = 0; st < n; ++st)
for (int ed = st + 1; ed <= n; ++ed){
int sum = 0;
for (int i = st; i < ed; ++i)
sum += nums[i];
if (ans < sum)
ans = sum;
}
return ans;
}
};


注意ans的设置。(int最小值-2147483648) 注意st, ed, i的区间。

Submission Details: 200 / 202 test cases passed. Status: Time Limit Exceeded

案例通过了,排除了死循环的嫌疑。但仍超时,说明时间复杂度太高。

三重循环,每重都是 O(n),因此时间复杂度是 O(n3) 。附加空间复杂度 O(1) 。

优化枚举,时间复杂度 O(n2)

优化代码时一般找最内层的循环,因为最内层的循环被执行的次数最多。

// 伪代码
for i ← 1 to n
sum ← 0
for j ← i to n
sum ← sum + a[j]
ans ← max(ans, sum)


class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
int ans = -2147483647;
for(int st = 0; st < n; ++st){
int sum = 0;
for(int ed = st + 1; ed <= n; ++ed){
sum += nums[ed - 1];
if (sum > ans)
ans = sum;
}
}
return ans;
}
};


Submission Details: 202 / 202 test cases passed. Status: Time Limit Exceeded

(比刚才多过了两个案例,LeetCode没有做好边界检测。)

仍然超时。时间复杂度 O(n2) 。附加空间复杂度 O(1) 。

继续优化,时间复杂度 O(n)

很多算法书上给出了如下的伪代码:

// 伪代码
sum ← 0      ans ← 0
for i ← 1 to n
sum ← sum + a[i]
ans ← max(sum, ans)
if (sum < 0)  sum ← 0


晦涩难懂。用去冗余的思路重写代码。

我们要求 max {a[i] + … + a[j]},设s[i] = a[0] + … + a[i],则问题转化为求max {s[j] - s[i-1]}。

若j固定(可以枚举j),s[j] = p,则max {s[j] - s[i-1]} = p - min s[i-1] (i < j)。

又,在寻找最小值的时候,有 min[0,6] = min(min[0,5] , min[6,6])。于是有下面的算法:

class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
int ans = -2147483647;
int sj = 0;
int minSi = 0;
int si = 0;
for (int j = 0; j < n; ++j){
sj += nums[j];
if (si < minSi)
minSi = si;
if (sj - minSi > ans){
ans = sj - minSi;
}
si += nums[j];
}
return ans;
}
};


Submission Details: 202 / 202 test cases passed. Status: Accepted

Runtime: 13 ms. Your runtime beats 23.20% of cpp submissions.

si和sj非常像,在for循环体的最后一句它们是相等的。可以继续优化。

变量替换,将sj替换为si + nums[j],于是有:

class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
int ans = -2147483647;
int minSi = 0;
int si = 0;
for (int j = 0; j < n; ++j){
if (si < minSi)
minSi = si;
if (si + nums[j] - minSi > ans){
ans = si + nums[j] - minSi;
}
si += nums[j];
}
return ans;
}
};


Submission Details: 202 / 202 test cases passed. Status: Accepted

Runtime: 9 ms. Your runtime beats 57.56% of cpp submissions.

我们新设一个int变量sum,表示si - minSi,那么上面的代码就可以改成:

class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
int ans = -2147483647;
int sum = 0;
for (int j = 0; j < n; ++j){
if (sum < 0)
sum = 0;
if (sum + nums[j] > ans){
ans = sum + nums[j];
}
sum += nums[j];
}
return ans;
}
};


Submission Details: 202 / 202 test cases passed. Status: Accepted

Runtime: 6 ms. Your runtime beats 98.41% of cpp submissions.

上面的代码又可以改成:

class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
int ans = -2147483647;
int sum = 0;
for (int j = 0; j < n; ++j){
sum += nums[j];
if (sum > ans)
ans = sum;
if (sum < 0)
sum = 0;
}
return ans;
}
};


从而与之前的伪代码一致。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: