算法基础-分治法求解最大子数组(Java)

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)));
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值