package algorithm;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 求解最大子数组问题,求解list中存在的最大和子数组
* 本例用单线程,当每个分解后处理耗时较长的时候,可以考虑使用多线程,且使用CyclicBarrier技术
* @author CLXU
*
*/
public class MaxSubArray {
//List 求和
public static int sumList(List<Integer> list){
int sum = 0;
for(int i=0;i<list.size();i++){
sum += list.get(i);
}
return sum;
}
//分治法求解
public static List<Integer> devideList(List<Integer> list){
int left_sum = Integer.MIN_VALUE;
int right_sum = Integer.MIN_VALUE;
int corss_sum = Integer.MIN_VALUE;
int size = list.size();
int mid = size/2;
//什么时候结束分解
if(size == 1){
return list;
}else{
//递归合并时,其返回的结果是动态变化的
List<Integer> left_list = devideList(list.subList(0, mid));
List<Integer> right_list = devideList(list.subList(mid, size));
List<Integer> cross_list = crossMiddleList(list,mid,size);
left_sum = sumList(left_list);
right_sum = sumList(right_list);
corss_sum = sumList(cross_list);
//最大子数组和存在3种情况,要么在中点左边,要么在中点右边,要么跨中点
if(left_sum>right_sum && left_sum > corss_sum){
return left_list;
}else if(right_sum > left_sum && right_sum > corss_sum){
return right_list;
}else{
return cross_list;
}
}
}
//求解和为跨越中点的情况,中点mid必须在左右都包含这个元素,不然会漏掉list.get(mid)这个元素
public static List<Integer> crossMiddleList(List<Integer> list,int mid,int size){
int left_sum = Integer.MIN_VALUE;
int right_sum = Integer.MIN_VALUE;
int sum = 0;
int left_point = mid;
int right_point = mid;
//求解左边
for(int i=mid;i>=0;i--){
sum += list.get(i);
if (sum > left_sum){
left_sum = sum;
//必须记录位置
left_point = i;
}
}
sum = 0;
//求解右边
for(int i=mid;i<size;i++){
sum += list.get(i);
if(sum > right_sum){
right_sum = sum;
right_point = i+1;
}
}
//因subList方法的前闭后开特性,所以才有right_point = i+1
return list.subList(left_point, right_point);
}
public static void main(String[] args) {
//List<Integer> list = new ArrayList<Integer>(Arrays.asList( 1, -2, 3, 10, -4, 7, 2, -5,-11,-11,-11,-11,-11,-11,-11));//整体在左边
//List<Integer> list = new ArrayList<Integer>(Arrays.asList( 1, -2, 3, 10, -4, 7, 2,-1,7,-5));//跨越中点
List<Integer> list = new ArrayList<Integer>(Arrays.asList( -1,4,10,-5,-2));//整体在边,在左边的mid节点
List<Integer> rlist = devideList(list);
System.out.println(rlist+ " sum = " + (sumList(rlist)));
}
}
算法基础-分治法求解最大子数组(Java)
最新推荐文章于 2021-12-16 21:38:15 发布