連続するサブアレイの最大合計
整数配列を入力します。配列内の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
この方法は、自分で示した例を計算することで理解できます。