码迷,mamicode.com
首页 > 其他好文 > 详细

求一数字序列的最大子段和(三种解法)

时间:2014-12-09 19:52:49      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:最大子段和   dp

import java.util.Scanner;

public class MaxSum { 
    public static void main(String[] args) { 
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入整数个数:");
        int N = scan.nextInt();
        int[] arr = new int[N];
        System.out.println("请输入整数序列(各数据间用空格隔开):");
        for(int i=0;i<N;i++){
        	arr[i] = scan.nextInt();
        }                           
        System.out.println("各算法所求最大子段和分别为:"); 
        System.out.println("分治算法最优值:" + maxSumDiv(arr, 0, arr.length - 1)); 
        System.out.println("==========================="); 
        maxSumDp(arr); 
        System.out.println("==========================="); 
        maxSumSimp(arr, 0, 0); 
    } 

    // 简单算法(需要O(n^2)计算时间)
    public static void maxSumSimp(int arr[], int bestx, int besty) { 
        int n = arr.length, sum = 0; 
        for (int i = 1; i <= n; i++) { 
            int thissum = 0;    //改变子段和的首数字时,须将当前的子段和清零
            for (int j = i; j <= n; j++) { 
                thissum += arr[j - 1]; 
                if (thissum > sum) { 
                    sum = thissum; 
                    bestx = i; 
                    besty = j; 
                } 
            } 
        } 
        System.out.println("简单算法最优值:" + sum); 
        System.out.println("最优解:" + bestx + "-->" + besty); 
    } 
 
    // 分治算法实现(需要O(nlogn)的计算时间)  
    public static int maxSumDiv(int[] arr, int left, int right) { 
        int sum = 0; 
        if (left == right) { 
            sum = arr[left] > 0 ? arr[left] : 0; 
        } else { 
            int center = (left + right) / 2; 
            int leftSum = maxSumDiv(arr, left, center); 
            int rightSum = maxSumDiv(arr, center + 1, right); 
            int s1 = 0; 
            int lefts = 0; 
            for (int i = center; i >= left; i--) { 
                lefts += arr[i]; 
                if (lefts > s1) { 
                    s1 = lefts; 
                } 
            } 
            int s2 = 0; 
            int rights = 0; 
            for (int i = center + 1; i <= right; i++) { 
                rights += arr[i]; 
                if (rights > s2) { 
                    s2 = rights; 
                } 
            } 
            sum = s1 + s2; 
            if (sum < leftSum) { 
                sum = leftSum; 
            } 
            if (sum < rightSum) { 
                sum = rightSum; 
            } 
        } 
        return sum; 
    } 
 
    // 动态规划算法实现(只需要O(n)计算时间和O(n)空间)  
    public static void maxSumDp(int[] arr) { 
        int sum = 0, b = 0, n = arr.length, bestx = 0, besty = 0; 
        for (int i = 1; i <= n; i++) { //b是累加和
            if (b > 0) { 
                b += arr[i - 1]; //和为正时累加
            } else { 
                b = arr[i - 1]; //否则将当前值赋给b
                bestx = i; 
            } 
            if (b > sum) { 
                sum = b; 
                besty = i; 
            } 
        } 
        System.out.println("动态规划算法最优值:" + sum); 
        System.out.println("最优解:" + bestx + "-->" + besty); 
    } 
}

运行结果:

bubuko.com,布布扣

作为DP的经典案例,仔细体会DP的基本思想:保存已解决的子问题的答案,避免大量的重复计算。

bubuko.com,布布扣

本文出自 “闲庭信步、” 博客,请务必保留此出处http://macxiao.blog.51cto.com/9606147/1588001

求一数字序列的最大子段和(三种解法)

标签:最大子段和   dp

原文地址:http://macxiao.blog.51cto.com/9606147/1588001

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!