效果展示:
1、
2、
3、
主要运用分治思想,可参考《算法导论》的4.1节。
源码:
/**
* 测试得到一个最大子数组(数组还有负数才有意义)---分治算法
* @author Smilexs
*
*/
public class TestMaxSubArray {
//最大子数组对象
private class SubArray{
int leftIndex;//子数组的 左索引
int rightIndex;//子数组的 右索引
int sum;//左索引到右索引直接 值的总和
public SubArray() {
// TODO Auto-generated constructor stub
}
public SubArray(int leftIndex,int rightIndex,int sum){
this.leftIndex = leftIndex;
this.rightIndex = rightIndex;
this.sum = sum;
}
public int getLeftIndex() {
return leftIndex;
}
public void setLeftIndex(int leftIndex) {
this.leftIndex = leftIndex;
}
public int getRightIndex() {
return rightIndex;
}
public void setRightIndex(int rightIndex) {
this.rightIndex = rightIndex;
}
public int getSum() {
return sum;
}
public void setSum(int sum) {
this.sum = sum;
}
}
/**
* 查找最大子数组
* @param array--数组
* @param leftIndex---左索引
* @param rightIndex---右索引
* @return
*/
public SubArray findMaxSubArray(int[] array,int leftIndex,int rightIndex){
if(leftIndex == rightIndex){
return new SubArray(leftIndex,rightIndex,array[leftIndex]);
}
else {
int mid = (leftIndex+rightIndex)/2;//中间位置
/**1、分治:从leftIndex --->mid*/
SubArray leftSubArray = findMaxSubArray(array, leftIndex, mid);
/**2、分治:从mid+1 --->rightIndex*/
SubArray rightSubArray = findMaxSubArray(array, mid+1, rightIndex);
/**3、分治:跨越中间的最大子数组*/
SubArray acrossSubArray = findAcrossMaxSubArray(array,leftIndex,mid,rightIndex);
/**4、取最大和*/
if(leftSubArray.getSum()>rightSubArray.getSum() && leftSubArray.getSum()>acrossSubArray.getSum()){
//第一种情况最大
return leftSubArray;
}else if(rightSubArray.getSum()>leftSubArray.getSum() && rightSubArray.getSum() > acrossSubArray.getSum()){
//第二种情况最大
return rightSubArray;
}else {
//第三种情况最大
return acrossSubArray;
}
}
}
/**
* 最大子数组,跨越中间的情况
* @param array--数组
* @param leftIndex--左索引
* @param mid--中间索引
* @param rightIndex--右索引
* @return
*/
private SubArray findAcrossMaxSubArray(int[] array, int leftIndex, int mid,
int rightIndex) {
SubArray resSubArray = new SubArray();
/**1、找左边-->中间的最大和*/
int leftSum = Integer.MIN_VALUE;
int sum =0;
for (int i = mid; i >=leftIndex; i--) {
sum += array[i];
if(sum > leftSum){
leftSum = sum;
resSubArray.setLeftIndex(i);
}
}
/**2、找中间-->右边的最大和*/
int rightSum = Integer.MIN_VALUE;
sum =0;
for (int i = mid+1; i <=rightIndex; i++) {
sum +=array[i];
if(sum > rightSum){
rightSum = sum;
resSubArray.setRightIndex(i);
}
}
resSubArray.setSum(leftSum+rightSum);//两边的总和
return resSubArray;
}
public static void main(String[] args) {
//初始化100个随机数
int N =20;
int[] array =new int[N];
for(int i=0;i<N;i++){
int temp = (int)(Math.random()*100);
if(temp%2==0){
temp = -temp;
}
array[i] = temp;
}
System.out.println("原数组:"+Arrays.toString(array));
TestMaxSubArray test = new TestMaxSubArray();
SubArray subArray = test.findMaxSubArray(array,0,array.length-1);
System.out.print("最大子数组:[");
for (int i = subArray.getLeftIndex(); i <subArray.getRightIndex(); i++) {
System.out.print(array[i]+",");
}
System.out.println(array[subArray.getRightIndex()]+"]");
System.out.println("最大子数组的和为:"+subArray.getSum() +" ,下标从"+subArray.getLeftIndex() +" -> "+subArray.getRightIndex());
}
}