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

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

运行结果:

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

时间: 2024-08-14 05:32:26

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

求一组数字序列的分布情况(java)

最近需要做一个正态分布的函数图像所以要处理一段double序列 写了这个算法  先上效果图: 核心思想: 1先根据步长计算每一个区间 2循环进行判断序列中每个数属于哪个区间 3用一个数组来保存每一个区间中 数的个数 这样就可以得到整个分布函数了 当然效率值得考虑 我的机器1百万以上的数据就会有问题了 这是一个double类型的例子 int型就更容易啦 上代码! 1 package com.huang.distribution; 2 3 import java.math.BigDecimal; 4

C语言--求字符串长度的三种解法

问题: 求一个字符串的三种解法 一.计数的方法 #include<stdio.h> #include<assert.h> int my_strlen( char* str) { int count=0; while (*str) { count++; str++; } return count; } int main(void) { char *arr = "abcef"; int ret = my_strlen(arr); printf("%d\n&

Windows10-UWP中设备序列显示不同XAML的三种方式[3]

阅读目录: 概述 DeviceFamily-Type文件夹 DeviceFamily-Type扩展 InitializeComponent重载 结论 概述 Windows10-UWP(Universal Windows Platform)增加一个新特性设备序列(DeviceFamily)特定视图,它允许开发者为指定的设备序列定义指定的XAML显示,(Desktop.Mobile.tablet.Iot等). 如果你想为不同的设备序列显示较多不一样的UI时,它是非常有用的.当然,使用Relative

经典面试题:求一个网页中出现次数最多的三种标签

1 const html=document.querySelector('html') 2 const htmlChild=html.children; 3 let obj={}; 4 function fn(children){ 5 for(let i of children){ 6 if(obj.hasOwnProperty(i.tagName)){ 7 obj[i.tagName]=obj[i.tagName]+1 8 }else{ 9 obj[i.tagName]=1; 10 } 11

BZOJ 1049 数字序列(LIS)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1049 题意:给出一个数列A,要求:(1)修改最少的数字使得数列严格递增:(2)在(1)的基础上使得修改的绝对值之和最小. 思路:对于第一问看起来像是求最长上升子 列,其实不是.我们想,若对于i<j,j能由i转移过来,那么需满足A[j]-A[i]>=j-i才行,这样我们发现只要A[j]-j& gt;=A[i]-i即可.因此令A[i]=A[i]-i,这样求LIS即可.对于第二问,

笔试算法题(34):从数字序列中寻找仅出现一次的数字 &amp; 最大公约数(GCD)问题

出题:给定一个数字序列,其中每个数字最多出现两次,只有一个数字仅出现了一次,如何快速找出其中仅出现了一次的数字: 分析: 由于知道一个数字异或操作它本身(X^X=0)都为0,而任何数字异或操作0都为它本身,所以当所有的数字序列都异或操作之后,所有出现两次的数字异或操作之后的结果都为0,则最后剩下的结果就是那个仅出现了一次的数字: 如果有多个数字都仅仅出现了一次,则上述的异或操作方法不再适用:如果确定只有两个数字只出现了一次,则可以利用X+Y=a和XY=b求解: 解题: 1 int findSin

codevs 2622 数字序列

2622 数字序列 提交地址:http://codevs.cn/problem/2622/ 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 黄金 Gold 题目描述 Description 给定一个长度为n的一个序列A1,A2,…,An,求序列中连续子序列的最大和. 例如:当输入为-5,3,5,7,-15,6,9,27,-36,10时,连续子序列6,9,27的和为42是最大值:而当序列变成-5,3,5,8,-15,6,9,27,-36,10时,连续子序列3,5,8,-15,6,9

【BZOJ 1049】 [HAOI2006]数字序列

1049: [HAOI2006]数字序列 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 979  Solved: 389 [Submit][Status] Description 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大. Input 第一行包含一个数n,接下来n个整数按顺序描述每一项的键值. Output 第一行一个整数表示最少需要改变多少

[Jobdu] 题目1544:数字序列区间最小值

题目描述: 给定一个数字序列,查询任意给定区间内数字的最小值. 输入: 输入包含多组测试用例,每组测试用例的开头为一个整数n(1<=n<=100000),代表数字序列的长度.接下去一行给出n个数字,代表数字序列.数字在int范围内.下一行为一个整数t(1<=t<=10000),代表查询的次数.最后t行,每行给出一个查询,由两个整数表示l.r(1<=l<=r<=n). 输出: 对于每个查询,输出区间[l,r]内的最小值. 样例输入: 5 3 2 1 4 3 3 1