LeetCode01連続サブアレイの最大合計(動的計画法)

連続するサブアレイの最大合計

整数配列を入力します。配列内の1つ以上の連続する整数がサブ配列を形成します。すべてのサブ配列の合計の最大値を見つけます。

必要な時間計算量はO(n)です。

例1:

入力:nums = [-2,1、-3,4、-1,2,1、-5,4]
出力:6
説明:連続するサブ配列[4、-1,2,1]の合計は最大の6です。

促す:

1 <= arr.length <= 10 ^ 5-100 <
= arr [i] <= 100

動的計画法分析:

一般的な考え方:ターゲット配列numと同じサイズの動的プログラミング配列dpを定義します。トラバーサル後、dp [i]の値は、要素num [i]で終わる連続サブ配列の最大合計です。実装の原則以下のとおりであります

状態の定義:

1.動的計画法リストdp、dp [i]が、要素nums [i]で終わる連続するサブ配列の最大合計を表すとします

最大合計を定義する理由dp [i]には要素nums [i]が含まれている必要があります。dp[i]がdp [i +1]に対して再帰的に正確であることを保証するため。

nums [i]が含まれていない場合、再帰中に質問の連続サブ配列要件は満たされません。

2.伝達方程式:dp [i-1]≤0の場合、dp [i-1]がdp [i]に負の寄与を持っていることを意味します。つまり、dp [i-1] + nums [i]はそうではありません。 nums [i]自体と同じくらい大きい。

dp [i-1]> 0の場合:dp [i] = dp [i-1] + nums [i]を実行します。

dp [i-1]≤0の場合:dp [i] = nums [i]を実行します。

3.初期状態:

dp [0] = nums [0]、つまり、nums [0]で終わる連続するサブ配列の最大合計はnums [0]です。

4.戻り値:

グローバル最大値を表すdpリストの最大値を返します。

ここに画像の説明を挿入

public int maxSubArray1(int[] nums){
    
    //暴力破解2优化,O(n^2)
        int n = -100;
        for (int i = 1; i < nums.length; i++) {
    
    
            int sum = 0;
            for (int j = i; j <= nums.length; j++){
    
    
                sum += nums[j];
                if (sum > n){
    
    
                    n = sum;
                }
            }
        }
        return n;
    }
public int maxSubArray2(int[] nums){
    
    //动态规划
        
        //创建一个同样大小的数组dp[i]表示以元素num[i]为结尾的连续子数组最大和
        int[] dp = new int[nums.length];
        dp[0]=nums[0];//初始化dp[0]
        for(int j = 1;j<nums.length;j++){
    
    
            //判断条件,dp[j-1]>0表示以元素num[i]为结尾的连续子数组最大和大于0
            // 即可对之后组成更大的连续子数组有正贡献
            //dp[j-1]<0,表示以元素num[i]为结尾的连续子数组最大和小于0,
            // 不再参与之后的连续子数组,子数组从新积累
            if(dp[j-1]>0){
    
    
                dp[j] = dp[j-1]+nums[j];
            }else{
    
    
                dp[j] = nums[j];
            }
        }
        int max = Integer.MIN_VALUE;
        for(int i = 0;i<dp.length;i++){
    
    //遍历dp,找到最大值
            if(dp[i]>max)
                max = dp[i];
        }
        return max;
    }

public int maxSubArray3(int[] nums) {
    
    //同样的功能大佬的代码简单到离谱,阿巴阿巴
        int res = nums[0];
        for(int i = 1; i < nums.length; i++) {
    
    
            nums[i] += Math.max(nums[i - 1], 0);
            res = Math.max(res, nums[i]);
        }
        return res;
    }

public class MaxSubArray {
    
    
    public static void main(String[] args) {
    
    
        Solution solution = new Solution();
        int[] arr = new int[]{
    
    -2,1,-3,4,-1,2,1,-5,4};//结果为6,ok
        System.out.println(solution.maxSubArray3(arr));
    }
}

要約:動的計画法の開始当初は、最も単純なブルートフォースソリューションでさえ独立して作成されていませんでしたが、これらの問題を解決するというアイデアが突然明確になり、強力すぎます。

ブルートフォースクラッキングは、0 [0]、[0,1]、[0,1,2]から[0,1,2、... n]まで、各サブアレイの合計のサイズを比較する二重ループです。 ]、[1から開始]、[1]、[1,2]、[1,2,3]から[1,2、... n]まで、2 ...から開始します。

sum(0,0)
sum(0,1) sum(1,1)
sum(0,2) sum(1,2) sum(2,2)
sum(0,3) sum(1,3) sum(2,3)

--------------------------------------->

この問題の動的計画法のアイデアは、num [i]で終わる各配列の最大のサブ配列を見つけて、それを配列dpに格納し、dpをトラバースして最大値を見つけることです。

マックス
sum(0,0) dp [0]
sum(0,1) sum(1,1) dp [1]
sum(0,2) sum(1,2) sum(2,2) dp [2]
sum(0,3) sum(1,3) sum(2,3) dp [3]
dp [j]

最大dp [j]の計算方法

dp [j] = dp [j-1] + nums [j]; dp [j-1]> 0

dp [j] = nums [j]; dp [j-1] <0

この方法は、自分で示した例を計算することで理解できます。

おすすめ

転載: blog.csdn.net/weixin_44529429/article/details/114136531