最大子序列和问题的3种算法
晚自习后半段,写了一道数据结构里的练习题——求最大子序列和。
其实,一般我们解决问题,为了让思路有条理,总会将问题划分,可以是大问题划分成子问题的形式,也可以是对问题所有结果的一些分类,然后一一解决。
由于最近没有使用Java,所以代码用Java实现。
依算法效率递增的顺序,其实亦是人本能思考递减的顺序,分别如下:
1.以子序列起始元素为划分,寻找该起始元素对应的最大子序列和,然后一一比较,得出最大值。
2.用分治的思想,将问题划分为子问题,然后递归地推导到原子项,然后综合。
1
package
maxSubSequence;
2
3
public
class
DivideAndConquer {
4
5
final
int
length
=
8
;
6
int
[] sequence
=
new
int
[length];
7
8
public
void
initialize(){
9
10
sequence[
0
]
=
4
;sequence[
1
]
=-
3
;
11
sequence[
2
]
=
5
;sequence[
3
]
=-
2
;
12
sequence[
4
]
=-
1
;sequence[
5
]
=
2
;
13
sequence[
6
]
=
6
;sequence[
7
]
=-
2
;
14
15
}
16
17
public
int
compute(){
18
return
realCompute(
0
,sequence.length
-
1
);
19
}
20
21
private
int
realCompute(
int
start,
int
end){
22
if
(start
==
end)
23
return
sequence[start];
24
int
leftMid
=
(start
+
end)
/
2
,rightMid
=
leftMid
+
1
;
25
int
leftMax
=
realCompute(start,leftMid);
26
int
rightMax
=
realCompute(rightMid,end);
27
int
leftBoundryMax
=
getLeftBoundryMax(start,leftMid);
28
int
rightBoundryMax
=
getRightBoundryMax(rightMid,end);
29
30
return
leftMax
>
rightMax
?
31
leftMax
>
leftBoundryMax
+
rightBoundryMax
?
leftMax:leftBoundryMax
+
rightBoundryMax
32
:rightMax
>
leftBoundryMax
+
rightBoundryMax
?
rightMax:leftBoundryMax
+
rightBoundryMax;
33
}
34
35
private
int
getRightBoundryMax(
int
rightMid,
int
end) {
36
37
int
tmp
=
0
,max
=
0
;
38
39
for
(
int
i
=
rightMid;i
<=
end;i
++
){
40
tmp
+=
sequence[i];
41
if
(tmp
>
max)
42
max
=
tmp;
43
}
44
return
max;
45
}
46
47
private
int
getLeftBoundryMax(
int
start,
int
leftMid) {
48
49
int
tmp
=
0
,max
=
0
;
50
51
for
(
int
i
=
leftMid;i
>=
start;i
--
){
52
tmp
+=
sequence[i];
53
if
(tmp
>
max)
54
max
=
tmp;
55
}
56
return
max;
57
}
58
59
public
static
void
main(String[] args){
60
DivideAndConquer divided
=
new
DivideAndConquer();
61
divided.initialize();
62
int
max
=
divided.compute();
63
System.out.println(max);
64
}
65
}
3.O(N)的联机算法,即完美算法。该算法扫描数据一次,且随时保存已处理的最大值。将每一个即将处理的可能最大项进行试探性处理,而后更新。注意到最大项必然是正项开始这一事实,其实该算法亦是一个划分,只是在已知已处理数据为负的情况下摒弃了算法1中的无效计算。从此观点看,算法的意义便在于让计算机尽量做有效,必要的比较。省去无意义或是重复的计算。
1 package maxSubSequence; 2 3 /** 4 * the central idea of the perfect algorithm to compute the max sub sequence 5 * is always keep the current largest result and use the incoming item to 6 * judge the undertaking "max" subsequence 7 * @author Yj_W 8 * 9 */ 10 public class Perfect { 11 final int length = 8; 12 int[] sequence = new int[length]; 13 14 public void initialize(){ 15 16 sequence[0]=4;sequence[1]=-3; 17 sequence[2]=5;sequence[3]=-2; 18 sequence[4]=-1;sequence[5]=2; 19 sequence[6]=6;sequence[7]=-2; 20 21 } 22 23 public void computeMaxSubSequence(){ 24 int max = 0,tmp = 0; 25 26 for(int i=0;i =0) 28 tmp +=sequence[i]; 29 else if((tmp += sequence[i]) < 0){ 30 tmp = 0; 31 } 32 33 if(tmp>max) 34 max = tmp; 35 } 36 System.out.println(max); 37 } 38 39 public static void main(String[] args){ 40 Perfect maxSub = new Perfect(); 41 maxSub.initialize(); 42 maxSub.computeMaxSubSequence(); 43 } 44 } 1
package
maxSubSequence;
2
3
/**
4
* the central idea of the perfect algorithm to compute the max sub sequence
5
* is always keep the current largest result and use the incoming item to
6
* judge the undertaking "max" subsequence
7
*
@author
Yj_W
8
*
9
*/
10
public
class
Perfect {
11
final
int
length
=
8
;
12
int
[] sequence
=
new
int
[length];
13
14
public
void
initialize(){
15
16
sequence[
0
]
=
4
;sequence[
1
]
=-
3
;
17
sequence[
2
]
=
5
;sequence[
3
]
=-
2
;
18
sequence[
4
]
=-
1
;sequence[
5
]
=
2
;
19
sequence[
6
]
=
6
;sequence[
7
]
=-
2
;
20
21
}
22
23
public
void
computeMaxSubSequence(){
24
int
max
=
0
,tmp
=
0
;
25
26
for
(
int
i
=
0
;i
<
sequence.length;i
++
){
27
if
(sequence[i]
>=
0
)
28
tmp
+=
sequence[i];
29
else
if
((tmp
+=
sequence[i])
<
0
){
30
tmp
=
0
;
31
}
32
33
if
(tmp
>
max)
34
max
=
tmp;
35
}
36
System.out.println(max);
37
}
38
39
public
static
void
main(String[] args){
40
Perfect maxSub
=
new
Perfect();
41
maxSub.initialize();
42
maxSub.computeMaxSubSequence();
43
}
44
}