整数数组中最大子数组的和的问题

一、题目:返回一个整数数组中最大子数组的和。

二、要求:

1、输入一个整形数组,数组里有正数也有负数。

2、数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。

3、求所有子数组的和的最大值。要求时间复杂度为O(n)

三、思路(学习徐利峰同学的):

1、分析可知,数组中的第一个数,是自己为一个子数组,从第二个数据开始往后每一个数有两种去路:

  1)隶属于之前的子数组(即,当之前的子数组之和加上这个数之后,大与当前数)。

  2)自己新创一个子数组(即,当之前的子数组之和加上这个数之后,小与当前数)。

2、遍历一遍数组,将所有可能是最大子数组的子数组的和存在相应子数组的最后一个位置。

3、遍历得出最大的子数组之和。

四、源代码:

package com.me.array;

import java.util.Scanner;

public class ArrayMax {
    
    public static void main(String[] args) {
        int a[] = new int [100];
        @SuppressWarnings("resource")
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入数组长度");
        int len = sc.nextInt();
        System.out.println("请输入"+len+"个数字");
        for(int i=0;i<len;i++) {
            a[i] = sc.nextInt();
        }
        int max = maxSubSum(a,len);
        System.out.println("所有子数组的和的最大值为:"+max);
        
    }
    static int maxSubSum(int[] a,int length) {
        int i=0;
        int len = length;
        for(i=1;i<len;i++){
            if(a[i]+a[i-1]>a[i]) {
                a[i]=a[i]+a[i-1];
            }
        }
        int ans=-100000;
        for(i=0;i<len;i++) {
            if(ans<a[i]) {
                ans = a[i];
            }
        }
        return ans;
    } 
}

五、运行测试:

 

 

 六、新要求:数组是环形数组。

七、改变后的思路(参考:https://blog.csdn.net/zlsjsj/article/details/80929160):

1、新要求下,这个问题的最优解一定是以下两种可能。
  1)最优解没有跨过a[n-1]到a[0],即和非环形数组一样了。
  2)最优解跨过a[n-1]到a[0],新问题。
2、对于第一种情况,我们可以按照非环形数组求法来求,为max1;

3、对于第二种情况,可以将原问题转化为数组的最小子数组和问题,再用数组全部元素的和减去最小子数组和,那么结果一定是跨过a[n-1]到a[0]情况中最大的子数组和,设为max2。最终结果即为max1与max2中较大的那个。
4、为什么这样求:数组元素“sum - 最小子数组和 = 跨过a[n-1]到a[0]情况中的最大子数组和”这一点有些疑问。我们可以这样理解:n个数的和是一定的,那么如果我们在这n个数中找到连续的一段数,并且这段数是所有连续的数的和最小的,那么“sum-最小子段和”的结果一定最大。故求得:跨过a[n-1]到a[0]情况中的最大子数组和。

八、更新代码:

package com.me.array;

import java.util.Scanner;

public class ArrayMax2 {
    
    public static void main(String[] args) {
        int a[] = new int [100];
        int a2[] = new int [100];
        int max = 0;
        int sum = 0;
        @SuppressWarnings("resource")
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入数组长度");
        int len = sc.nextInt();
        System.out.println("请输入"+len+"个数字");
        for(int i=0;i<len;i++) {
            a[i] = sc.nextInt();
            a2[i] = a[i];
            sum += a[i];
        }
        int min = minSubSum(a,len);
        int max2 = maxSubSum(a,len);
        max = sum - min;
        if(max>max2) {
            System.out.println("环型数组的所有子数组的和的最大值为:"+max);
        }else {
            System.out.println("环型数组的所有子数组的和的最大值为:"+max2);
        }        
    }
    static int maxSubSum(int[] a,int length) {
        int i=0;
        int len = length;
        for(i=1;i<len;i++){
            if(a[i]+a[i-1]>a[i]) {
                a[i]=a[i]+a[i-1];
            }
        }
        int ans=-100000;
        for(i=0;i<len;i++) {
            if(ans<a[i]) {
                ans = a[i];
            }
        }
        return ans;
    } 
    static int minSubSum(int[] a,int length) {
        int i=0;
        int len = length;
        for(i=1;i<len;i++){
            if(a[i]+a[i-1]<a[i]) {
                a[i]=a[i]+a[i-1];
            }
        }
        int ans=100000;
        for(i=0;i<len;i++) {
            if(ans>a[i]) {
                ans = a[i];
            }
        }
        return ans;
    } 
}

九、运行测试:

 

 

 十、总结

  这次课堂测试我一步都没有做出来,反省后找到原因可能是因为,自从上学期老师上课不在靠java的算法测试后,就没有再针对练习过java编程,只学习和练习了与Javaweb相关的一些用法。更主要的是因为,假期的放纵,,,其次就是在家听课练习很浮躁,很懒,很贪玩。这次测试给我敲响了警钟,我明白之后要制定学习计划并认真按照计划执行,高质量完成老师的任务,自己多加练习。

 

posted @ 2020-02-25 20:24  程序那点事  阅读(592)  评论(0编辑  收藏  举报