一个有N个元素的一维数组(a[0], a[1]….a[n-1]),我们定义连续的a[i] ~ a[j],0<= i, j <=n-1为子数组。
显然这个数组中包含很多子数组,请求最大的子数组之和。
如果不想时间复杂度,用遍历所有可能子数组,然后找出最大值就可以了。
现在如果要求时间复杂度最小,那么肯定是要DP解的。
我们假设定义两个数组:
all[i]:表示从i~n-1,最大的子数组之和。
start[i]:表示包含i,并且从i~n-1,最大子数组之和。
all[i]中max只有三种可能:
(1) a[i]单独就是最大,之后再加一个就会变小。
(2)a[i]+…a[j]最大,即start[i]最大
(3)a[x]+..a[j]最大,即不包含i的后序某一个子数组和最大。
最终,最大的子数组之和是all[0]。根据上述3个可能,很容易写出如下递推式:
start[i] = max (a[i], a[i]+start[i+1])
all[i] = max(start[i], all[i+1])
注意我们把上面max(a, b, c)拆成了两个max(a, b)
由于我们在计算start[i]/all[i]时候需要start[i+?]的值,所以我们从后向前递推dp。
代码如下,时间复杂度O(n):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
max
(
int
a
,
int
b
)
{
if
(
a
>
b
)
{
return
a
;
}
else
{
return
b
;
}
}
int
max_sum
(
int
*
arr
,
int
n
)
{
// Helper array
int
i
;
int
*
start
=
(
int
*
)
malloc
(
sizeof
(
int
)
*
n
)
;
int
*
all
=
(
int
*
)
malloc
(
sizeof
(
int
)
*
n
)
;
int
final
;
if
(
!
start
||
!
all
)
{
return
-
1
;
}
memset
(
start
,
0
,
sizeof
(
int
)
*
n
)
;
memset
(
all
,
0
,
sizeof
(
int
)
*
n
)
;
// dp
start
[
n
-
1
]
=
arr
[
n
-
1
]
;
all
[
n
-
1
]
=
arr
[
n
-
1
]
;
for
(
i
=
n
-
2
;
i
>=
0
;
i
--
)
{
start
[
i
]
=
max
(
arr
[
i
]
,
arr
[
i
]
+
start
[
i
+
1
]
)
;
all
[
i
]
=
max
(
start
[
i
]
,
all
[
i
+
1
]
)
;
}
final
=
all
[
0
]
;
// Free helper array
free
(
start
)
;
free
(
all
)
;
return
final
;
}
int
main
(
)
{
//int arr[6] = {1, -2, 3, 5, -3, 2}; // 8
int
arr
[
6
]
=
{
0
,
-
2
,
3
,
5
,
-
1
,
2
}
;
// 9
//int arr[5] = {-9, -2, -3, -5, -3}; // -2
printf
(
"max sum of sub_arr: %d \n"
,
max_sum
(
arr
,
sizeof
(
arr
)
/
sizeof
(
int
)
)
)
;
return
0
;
}
|