算法导论--最大子数组

问题介绍

最大子数组问题:

给定一个整数数组nums,找到具有最大总和并返回其总和的连续子数组(包含至少一个数字)。
例:

1
2
3
输入: [ -2,1,-3,4,-1,2,1,-5,4],
输出: 6
说明: [4,-1,2,1]的最大和= 6。

思考

思路1:暴力解法:

两层遍历,外层遍历定位每个数字,内层遍历依次从本数字往后,计算sum,并与max_sum进行比较,如果sum > max_sum,则替换,并记下下标值。

思路2:分治法:

把原数组分解成左右两部分,一直递归下去,所以存在3种答案情况:

  1. 最大子数组在左侧
  2. 最大子数组在右侧
  3. 最大子数组横跨中间值(最小规模即2个数,即左右两数相加)

结果集数据结构

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
public class Arrayobj {
private int startindex;
private int endindex;
private int value;
public Arrayobj(int startindex, int endindex, int value) {
this.startindex = startindex;
this.endindex = endindex;
this.value = value;
}
public int getStartindex() {
return startindex;
}
public void setStartindex(int startindex) {
this.startindex = startindex;
}
public int getEndindex() {
return endindex;
}
public void setEndindex(int endindex) {
this.endindex = endindex;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public String toString() {
return "Arrayobj{" +
"startindex=" + startindex +
", endindex=" + endindex +
", value=" + value +
'}';
}
}

FIND_MAX_CROSSING_SUBARRAY

算法导论中将计算横跨左右的最大子数组算法单独列出来了:

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
/**
* @Author:Saintyun
* @Date:2018/8/8 21:26
* @Expression:最大子数组 crossing subarray
**/
public static Arrayobj findMaxCrossingSubarray(Integer[] A,Integer low,Integer mid,Integer high){
int left_sum = Integer.MIN_VALUE;
int sum = 0;int max_left = 0;
for(int i=mid;i>=low;i--){
sum = sum+A[i];
if(sum>left_sum){
left_sum = sum;
max_left = i;
}
}
int right_sum = Integer.MIN_VALUE;
sum = 0;int max_right = 0;
for(int i=mid+1;i<=high;i++){
sum = sum+A[i];
if(sum > right_sum){
right_sum = sum;
max_right = i;
}
}
return new Arrayobj(max_left,max_right,left_sum+right_sum);
}

FIND_MAX_SUBARRAY

分别查找数组左部,右部,横跨部分的最大子数组下标,以及总数,合并操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* @Author:Saintyun
* @Date:2018/8/8 21:36
* @Expression: 最大子数组 分治算法 求解
**/
public static Arrayobj findMaxSubarray(Integer [] A,Integer low,Integer high){
// 最小规模返回条件
if (low == high)return new Arrayobj(low,high,A[low]);
else{
int mid = (low + high)/2;
Arrayobj left = findMaxSubarray(A,low,mid);
Arrayobj right = findMaxSubarray(A,mid+1,high);
Arrayobj cross = findMaxCrossingSubarray(A,low,mid,high);
//比较left_sum,right_sum,cross_sum,最小规模的比较操作
if(left.getValue() > right.getValue() && left.getValue()>cross.getValue())
return left;
else if(right.getValue()>left.getValue()&& right.getValue()>cross.getValue())
return right;
else return cross;
}
}

测试结果

1
2
3
4
5
public static void main(String[] args) {
Integer [] testarray = {-5,3,1,-2,3,-10,3,-1,0,2};
Arrayobj obj= Solution.findMaxSubarray(testarray,0,9);
System.out.println(obj.toString());
}
1
Arrayobj{startindex=1, endindex=4, value=5}

递归过程

以上述实例为例: