単純なものから難しいものまで、最も単純な問題から始めましょう。
整数配列が与えられた場合、最大のサブ配列の合計は何ですか?配列は連続している必要があります。
入力例: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