[インタビュークラシック] 1次元から2次元へ-最大のサブ配列から最大のサブマトリックスまで

単純なものから難しいものまで、最も単純な問題から始めましょう。

整数配列が与えられた場合、最大のサブ配列の合計は何ですか?配列は連続している必要があります。

入力例:nums = [-3,4、-1,2,1、-5,4]

出力サンプル:6、つまり、連続するサブ配列[4、-1,2,1]の合計が最大です

アイデアは単純です:

DPにすることもできますが、必須ではありません。これは次のように理解できます。既存の配列の合計が0より大きい場合、この時点で合計に寄与する必要があるため、それに基づいて(if sum > 0 : sum += nums[i]を累積します。既存の配列の合計が0より小さい場合。 、それからそれは別のストーブを開始する必要があります(if sum < 0 : sum = nums[i])。

コードも単純です:

class Solution {
    
    
    public int maxSubArray(int[] nums) {
    
    
        int max = nums[0];
        int sum = nums[0];
        for (int i = 1; i < nums.length; i++) {
    
    
            sum = nums[i] + (sum > 0 ? sum : 0);
            max = Math.max(max, sum);
        }
        return max;
    }
}

 
 

さらに、最大の配列合計ではなく最大の配列位置が必要な場合は、次のようにします。

アイデアは難しくありません:

それでも最大値max、array、sumを維持する必要があります。配列の左側の境界を示す開始を設定し、右側の境界は現在の位置iであり、特に変数を設定する必要はありません。

重要な質問を検討してください。いつ更新が開始されますか?合計が0未満であるため、最初からやり直すときに更新を開始します。

コードは次のように表示されます。

class Solution {
    
    
    public int[] maxSubArray(int[] nums) {
    
    
        int start = 0;
        int sum = nums[0];
        int max = nums[0];
        int[] res = new int[2];
        for (int i = 1; i < nums.length; i++) {
    
    
            if (sum > 0) {
    
    
            	// 之前的数组和有"贡献",因此在其基础上累加
                sum += nums[i];
            } else {
    
    
            	// 之前的数组无"贡献",因此另起炉灶
                sum = nums[i];
                start = i;
            }
            if (sum > max) {
    
    
                max = sum;
                res[0] = start;
                res[1] = i;
            }
        }
        return res;
    }
}

 
 

問題は昇順です。配列が行列になると、最大値とその位置を見つける方法は次のようになります。

M×N行列が与えられた場合、連続性を必要とする最大の部分行列の位置を返します。戻り値の形式は配列[r1、c1、r2、c2]です。

このアイデアにより、突然気付くでしょう。連続する行を1つの行にマージすると、複数の最大のサブ配列の問題になりませんか?

ここに画像の説明を挿入
写真を見ると、コードのアイデアは明確です。

上限の上限と下限の下限を設定し、([top、bottom])の間の線をマージして、最大値を更新しようとします。最終結果の「上下」は現在の上限と下限であり、 「左と右」はソリューションの中で最大です。サブアレイの問題が発生したときに引き出します。

行をマージするとき、プレフィックスと最適化を実行できます。つまり、プレフィックスと配列が列ごとに生成されます。

最終的なコードは次のとおりですが、それでも十分にエレガントです。

class Solution_6789 {
    
    
    public int[] getMaxMatrix(int[][] matrix) {
    
    
        int m = matrix.length;
        int n = matrix[0].length;
        int max = matrix[0][0];		// 全局最大值
        int[] res = new int[4];		// 最终结果

        // 构造列的前缀和
        int[][] preSum = new int[m + 1][n];
        for (int i = 1; i < m + 1; i++) {
    
    
            for (int j = 0; j < n; j++) {
    
    
                preSum[i][j] = preSum[i - 1][j] + matrix[i - 1][j];
            }
        }

        // 合并行
        for (int top = 0; top < m; top++) {
    
    
            for (int bottom = top; bottom < m; bottom++) {
    
    
                // 构造一维矩阵
                int[] arr = new int[n];
                for (int i = 0; i < n; i++) {
    
    
                    arr[i] = preSum[bottom + 1][i] - preSum[top][i];
                }
                // 最大子数组问题
                int start = 0;
                int sum = arr[0];
                for (int i = 1; i < n; i++) {
    
    
                    if (sum > 0) {
    
    
                        sum += arr[i];
                    } else {
    
    
                        sum = arr[i];
                        start = i;
                    }
                    if (sum > max) {
    
    
                        max = sum;
                        res[0] = top;
                        res[1] = start;
                        res[2] = bottom;
                        res[3] = i;
                    }
                }
            }
        }

        return res;
    }
}

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

END END E N D

おすすめ

転載: blog.csdn.net/m0_46202073/article/details/115175436