最大子数组和的动态规划实现(java)

一,最大子数组和

1.什么是子数组:数组中一段连续的序列

2.什么是最大子数组:子数组各个值相加的和最大

这在我们之前学过的最大子数组的分治实现中都有提到。

分治法求解最子数组和的关键步骤就是分解原问题,求跨中点的最大子数组和,重点在于

而这次我们采用动态规划来实现,进一步优化分治算法。

二,动态规划步骤

 


三,动态规划表格及伪代码详解

 这里附上我手写的动态规划表格

D[ ]数组用来记录动态规划的最优解;Rec[ ]用来记录尾,也就是如果D[i+1]<=0,我们就抛弃这个尾,从当前位置重新记录;Max当然就是输出最终结果;sub就是最大子数组序列。

 下面附上伪代码(感谢一波学校教算法的耿老师,伪代码相当不错)

 根据伪代码就可轻松写出代码

到这里,我们就能意识到,既然从尾到头可以计算这个问题,那么从头到尾是否也能可以呢,答案当然是肯定的,原理与此大致相同,在求解动态规划的状态方程上有些区别(毕竟顺序发生变化了嘛)。

如下图我手写的表格所示


 四,代码部分

1,从尾到头方法

本次调试非常顺利,一遍就出结果了,唯一要注意的就是伪代码中数组都是从1开始,而我的代码中数组是从0开始,原理都一样,就是给每个遍历数组的标记都减一。

完整代码如下:

import java.util.Arrays;
public class Max_Continuous_Subarray {
    public void DP(int[] arr,int n){
        //初始化
        int [] D=arr.clone();
        int [] Rec=new int[n];
        for(int i=0;i<n;i++){
            Rec[i]=n-1;
        }
        //动态规划
        for(int i=n-2;i>=0;i--){
            if(D[i+1]>0){
                D[i]=arr[i]+D[i+1];
                Rec[i]=Rec[i+1];
            }else{
                D[i]=arr[i];
                Rec[i]=i;
            }
        }
        //输出结果
        System.out.println("原数组为:"+Arrays.toString(arr));
        System.out.println("动态规划最优解为:"+Arrays.toString(D));
        System.out.println("记录尾数组为:"+Arrays.toString(Rec));
        Find(D,Rec,arr,n);
    }
    public void Find(int[] D,int[] Rec,int[] arr,int n){
        //查找解
        int Smax=D[0];
        int l = 0,r=0;
        for(int i=1;i<n;i++){
            if(Smax<D[i]){
                Smax=D[i];
                l=i;
                r=Rec[i];
            }
        }
        System.out.print("最大子数组序列为:");
        for(int i=l;i<=r;i++){
            System.out.print(arr[i]+" ");
        }
    }
    public static void main(String[] args) {
        Max_Continuous_Subarray dp=new Max_Continuous_Subarray();
        int[] arr={31,-41,59,26,-53,58,97,-93,-23,84};
        dp.DP(arr,arr.length);
    }
}

 

2,从头到尾方法

 下面列出从头到尾方法的代码

import java.util.Arrays;
public class Max_Continuous_Subarray2 {
    public void DP(int[] arr,int n){
        //初始化
        int [] b=arr.clone();
        int [] Rec=new int[n];
        for(int i=0;i<n;i++){
            Rec[i]=0;
        }
        //动态规划
        for(int j=1;j<n;j++){
            if(b[j-1]>0){
                b[j]=b[j-1]+arr[j];
                Rec[j]=Rec[j-1];
            }else{
                b[j]=arr[j];
                Rec[j]=j;
            }
        }
        //输出结果
        System.out.println("原数组为:"+Arrays.toString(arr));
        System.out.println("动态规划最优解为:"+Arrays.toString(b));
        System.out.println("记录尾数组为:"+Arrays.toString(Rec));
        Find(b,Rec,arr,n);
    }
    public void Find(int[] b,int[] Rec,int[] arr,int n){
        //查找解
        int Smax=b[0];
        int l = 0,r=0;//这里原本l代表数组头,r代表数组尾,现在要进行互换
        for(int i=1;i<n;i++){
            if(Smax<b[i]){
                Smax=b[i];
                l=i;
                r=Rec[i];
            }
        }
        System.out.print("最大子数组序列为:");
        for(int i=r;i<=l;i++){
            System.out.print(arr[i]+" ");
        }
    }
    public static void main(String[] args) {
        Max_Continuous_Subarray2 dp=new Max_Continuous_Subarray2();
        int[] arr={31,-41,59,26,-53,58,97,-93,-23,84};
        dp.DP(arr,arr.length);
    }
}

 


 3,注意项和方法对比

 从头到尾方法和从尾到头方法区别并不是很大,主要就在动态规划的状态方程上有区别,另外,还是要注意数组下标都减了1。如下所示。

//动态规划
for(int j=1;j<n;j++){
    if(b[j-1]>0){
        b[j]=b[j-1]+arr[j];
        Rec[j]=Rec[j-1];
    }else{
        b[j]=arr[j];
        Rec[j]=j;
    }
}

 为方便区分,我将这两种方法的状态方程代码单独截图列出

 有任何问题,还请评论区指正,谢谢。

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值