最大子数组和(贪心算法和动态规划法)

注意找的是连续数组!!

一,动态规划法 

 class Solution {
    public int maxSubArray(int[] nums) {
        //创建一个与nums等大的数组dp
       int[] dp=new int[nums.length];
        //dp[i]表示以nums[i]结尾的数组的最大子数组的和
       dp[0]=nums[0];
       for(int i=1;i<nums.length;i++){
       // 如果dp[i-1]+nums[i]>=nums[i],那么nums[i]的最大子数组就是nums[i-1]的最大子数组加上nums[i];如果dp[i-1]+nums[i]比nums[i]还小的话,那nums[i]的最大子数组就是它本身
           if(dp[i-1]+nums[i]>=nums[i]){
               dp[i]=dp[i-1]+nums[i];
           }else{
               dp[i]=nums[i];
           }
       }
      //整个nums数组的最大子数组就是以nums数组中每个元素结尾的数组的最大子数组的最大值
        //所以再遍历一遍dp数组找出最大值
       return max(dp);
    }
    public int max(int[] dp){
        int max=dp[0];
        for(int i=0;i<dp.length;i++){
             if(dp[i]>=max){
                 max=dp[i];
             }
        }
        return max;
    }

1,确定子问题

例如题目所给的nums=[5,4,-1,7,8]

我们可以把这个问题分解为:

以5结尾的连续最大子数组和是多少?

以4结尾的连续最大子数组和是多少?

以-1结尾的连续最大子数组和是多少?

以7结尾的连续最大子数组和是多少?

以8结尾的连续最大子数组和是多少?

2,找到关系,确立动态转移方程

可以发现,以4 结尾的连续数组就是以5结尾的连续数组加上4,如果以5 结尾的连续的最大子数组的和加上4比4大,那么以4结尾的最大子数组就是以5结尾的连续 最大子数组数 加上4;否则就是4 本身

那我们创建一个与nums等大的dp数组,dp[i]表示以nums[i]结尾的连续的最大子数组的和

dp[i]={   dp[i−1]+nums[i],     if             dp[i]>0  (dp[i−1]+nums[i]>num[i])

             nums[i],​                   if            dp[i−1]≤0​          }

整个nums数组的最大子数组就是以nums数组中每个元素结尾的数组的最大子数组的最大值
所以再遍历一遍dp数组找出最大值

二,贪心算法

从前往后的整个遍历以遍数组,用max表示目前最大的子数组和,不断的更新max,最后返回max。用sum表示在nums[i]上的最大数组加上nums[i],max取max和sum中的最大值(不断更新max),如果sum<0,就不能加上nums[i]了,连续数组就直接断掉,从nums[i+1]开始重新找,因为nums[i+1]加上sum相当与加了一个负数,还不如不加所以直接把sum改为0.

最后返回max即可

但是我们忽略了一种情况:全是负数,这样sum不可能为正却返回了0

所以可以在最前面把这种情况判断出来返回数组中最大的一个负数即可

class Solution {
    public int maxSubArray(int[] nums) {
       int sum=0;
       int max=Integer.MIN_VALUE;
       if(nums.length==1){
           //如果数组只有一个元素就直接返回这个元素
           return nums[0];
       }
             //判断是否全为负数
    for(int i=0;i<nums.length;i++){
        if(nums[i]>=0){
            // 但凡有一个不是负数就跳出
            break;
        }
        if(i==nums.length-1&&nums[nums.length-1]<0){
            //能够遍历到最后一个元素并且最后一个元素为负数,就返回数组中的最大数
            max=max(nums);
            return max;
        }
    }
       for(int i=0;i<nums.length;i++){
           if(sum+nums[i]<0){
                   //如果nums[i]小到能把sum给抵消,连续数组断掉,从下一个重新找
                    sum=0;
           }else{
               sum=sum+nums[i];
               //不断更新max
               max=Math.max(sum,max);
           }
       }
       return max;
    }
    public int max(int[] nums){
        int max=nums[0];
        for(int i=1;i<nums.length;i++){
            if(nums[i]>max){
                max=nums[i];
            }
        }
        return max;
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

荔枝味啊~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值