求最大子数组!!(动态规划)

给定一个数组,当中有正负数,求当中的一段“子数组”(即任意长度,连续的数字),使得这个“子数组”的和是所有“子数组”和中最大的,
如给定的数组为12, -8, 5, 66, -21, 0 ,35, -44,7,则最大的和的子数组为{12, -8, 5, 66, -21, 0 ,35},最大的和为89.

这就是个简单的典型的“动态规划”题目。

数组:x1,x2,x3,……xn
思路,首先是寻找最优子结构,这点要依靠一些经验规则。
这里的最优子结构就是
f(i)定义为以xi结尾的最大字串和。
那么f(i+1)就可以考虑
如果xi+1大于等于0或者f(i) + xi+1 > 0,那么f(i+1) = f(i) + xi+1;
如果f(i) + xi+1  <= 0,那么f(i+1) = 0;
递推公式就是有了。下面用DP的典型结构给出代码:

public   class  MaxSubSequence  {    
    
public static void main (String[] args) {
        
int[] input = new int[]{3,73,-95,42,43,29,-30,-87,74,-53,22,74,-91,-1,-27,-8,-14,26,-67,-74};
        
        
int[] fDp = new int[input.length];    //f for dp
        
//process first element
        if (input[0> 0)
            fDp[
0= input[0];
        
for (int i = 1;i < input.length;++i){
            
if (fDp[i-1]+input[i] > 0)
                fDp[i] 
= fDp[i-1]+input[i];
            
else
                fDp[i] 
= 0;
        }

        
//find the max value in fDp
        int maxSun = 0;
        
for (int sum : fDp)
            
if (sum > maxSun)
                maxSun 
= sum;
                
        System.out.println(
"max sum : " + maxSun);
    }

    
}
  程序输出117
这里得到了正确结果,但是要求字串的位置还没实现,其实很简单,修改程序,从结果反推过程就可得到。

上面是个典型的一维DP结构的解法,算法复杂度是O(n),但是想更直接的求解,可以优化算法,不用显示创建DP数组。

class  MaxSubSequence2 {
    
public static void main (String[] args) {
        
int[] input = new int[]{3,73,-95,42,43,29,-30,-87,74,-53,22,74,-91,-1,-27,-8,-14,26,-67,-74};
        
        
int fst = -1,snd = -1,tFst = 0,tSnd = 0,maxSum = 0,currSum = 0;
        
for (;tSnd < input.length;++tSnd){
            currSum 
+= input[tSnd];
            
if (currSum > maxSum){
                maxSum 
= currSum;
                fst 
= tFst;
                snd 
= tSnd;
            }

            
if (currSum < 0){
                currSum 
= 0;
                tFst 
= tSnd+1;
            }

        }

        
        System.out.println(
"max sum : " + maxSum + " from " + fst + " to " + snd);
    }

}


考虑全负数的数组,修改一点就能满足。

class  MaxSubSequence2
    
public static void main (String[] args) 
        
int[] input = new int[]{-95,-30,-87,-53,-91,-1,-27,-8,-14,-67,-74}
            
        
int fst = -1,snd = -1,tFst = 0,tSnd = 0,maxSum = 0,currSum = 0
        
int maxNum=Integer.MIN_VALUE;
            
          
for (;tSnd < input.length;++tSnd)
              
            currSum 
+= input[tSnd]; 
            
if(input[tSnd]>maxNum){
                maxNum
=input[tSnd];
            }
    
            
if (currSum > maxSum)
                maxSum 
= currSum; 
                fst 
= tFst; 
                snd 
= tSnd; 
            }
 
                
            
if (currSum < 0)
                currSum 
= 0
                tFst 
= tSnd+1
            }
 
                
        }

        
if(currSum==0){
            System.out.println(
"max sum : " + maxNum + " It's [" +maxNum+"]" );//显示第一个最大负数
            
return;
        }

         System.out.println(
"max sum : " + maxSum + " from " + fst + " to " + snd); 
    }
 
}
 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值