最近在看《数据结构与算法》,因此将自己的笔记写在这里,留给以后复习时看。
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
对于该题目,我们很容易想到一个时间复杂度为
O
(
N
3
)
O(N^3)
O(N3)的算法。
class Solution {
public int maxSubArray(int[] array){
int len = array.length, maxSum = 0;
for(int begin = 0; begin<len; begin++){
for(int end = begin; end<len; end++){
int sum = 0;
for(int index = begin; index<=end; index++){
sum+=array[index];
}
if(sum > maxSum){
maxSum=sum;
}
}
}
return maxSum;
}
}
上面的代码,以 begin 为左边界,end 为右边界,依次计算左边界到右边界之间的数字和,同时更新 maxSum ,则maxSum即为所求结果。
上面的算法显然时间复杂度过高,则我们可以将其改进到
O
(
N
2
)
O(N^2)
O(N2)
class Solution {
public int maxSubArray(int[] array) {
int len = array.length, maxSum = 0;
for (int begin = 0; begin < len; begin++) {
int sum = 0;
for (int end = begin; end < len; end++) {
sum += array[end];
if (sum > maxSum) {
maxSum = sum;
}
}
}
return maxSum;
}
}
某种意义上,该 O ( N 2 ) O(N^2) O(N2)的算法比上面的 O ( N 3 ) O(N^3) O(N3)的算法更好理解,这里不再赘述。
看起来以上代码已经无法优化,但我们仍能给出时间复杂度为 O ( N ) O(N) O(N)的算法
class Solution {
public int maxSubArray(int[] array) {
int len = array.length, maxSum = 0, sum = 0;
for (int begin = 0; begin < len; begin++) {
sum += array[begin];
if (sum < 0) {
sum = 0;
} else {
if (sum > maxSum) {
maxSum = sum;
}
}
}
return maxSum;
}
}
对于该代码的时间复杂度为 O ( N ) O(N) O(N)是很好证明的,但该代码的正确性却不是那么容易理解,以下我们给出解释。
首先说一句,当传入的数组参数全部为负数时,我们给出的答案为0,因为此时我们可以一个数字都不选,即子数组的长度为0。
设 i <= mid <= j。
对于一个数组array,若有
∑
i
n
d
e
x
=
i
m
i
d
a
r
r
a
y
[
i
n
d
e
x
]
<
0
\sum _{index=i}^{mid}array[index]<0
index=i∑midarray[index]<0,则
∑
i
n
d
e
x
=
i
j
a
r
r
a
y
[
i
n
d
e
x
]
<
∑
i
n
d
e
x
=
m
i
d
j
a
r
r
a
y
[
i
n
d
e
x
]
\sum _{index=i}^{j}array[index]<\sum_{index=mid}^{j}array[index]
index=i∑jarray[index]<index=mid∑jarray[index],那么我们可以舍弃 array[i]到array[mid] 这一部分,重新考虑以 mid+1 为开始下标,之后的数字作为最大子串。