最大サブアレイ合計 はコンピュータサイエンスで有名な問題です。
少なくとも2つの解決策があります。
ビデオの中で チュートリアル 作者は力ずくの方法がO(n^2)
であると述べ、読んでいる 別の答え ある人はそれをO(n^2)
と考えているO(n^3)
だと思います
強引な力はO(n^2)
またはO(n^3)
ですか?さらに重要なことに、ブルートフォースメソッドで実行した分析を説明して、それがO(?)
であることを確認できますか?
まあ、それは力がどれほど野蛮であるかに依存します。
すべての_(i, j): i <= j
_ペアを生成し、その間の合計を計算すると、O(n^3)
になります。
_....
for (int i = 0; i < n; i++)
for (int j = i; j < n; j++) {
int sum = 0;
for (int k = i; k <= j; k++)
sum += a[k];
if (sum > max)
max = sum;
}
_
すべての位置から開始して現在の合計を計算すると、それはO(n^2)
です。
_....
for(int i = 0; i < n; i++) {
int sum = 0;
for (int j = i; j < n; j++) {
sum += a[j];
if (sum > max)
max = sum;
}
}
_
最大部分和問題の3つの解決策を次に示します。 solve1()
はO(N)時間で実行され、solve2()
はO(N ^ 2)で実行され、solve3()
はO(N ^ 3)。solve1()
はKadaneのアルゴリズムとして知られていることに注意してください。
O(N ^ 2)関数とO(N ^ 3)関数の違いは、O(N ^ 2)関数では、end
インデックスがインクリメントされるたびに、合計が暗黙的に計算されることです。 O(N ^ 3)関数の場合、合計はstart
とend
の間の3番目の明示的なループで計算されます。
すべての入力値が負の場合を処理するために、3つのアプローチすべてにコードを追加しました。
public class MaximumSubarraySum {
/**
* Solves the maximum subarray sum in O(N) time.
*/
public static int solve1(int[] input) {
int sum = input[0];
int bestSum = sum;
for (int i = 1; i < input.length; i++) {
sum = Math.max(input[i], input[i] + sum);
bestSum = Math.max(sum, bestSum);
}
return bestSum;
}
/**
* Solves the maximum subarray sum in O(N^2) time. The two indices
* 'start' and 'end' iterate over all possible N^2 index pairs, with
* the sum of input[start, end] always computed for every 'end' value.
*/
public static int solve2(int[] input) {
int bestSum = -Integer.MAX_VALUE;
for (int start = 0; start < input.length; start++) {
// Compute the sum of input[start, end] and update
// 'bestSum' if we found a new max subarray sum.
// Set the sum to initial input value to handle Edge case
// of all the values being negative.
int sum = input[start];
bestSum = Math.max(sum, bestSum);
for (int end = start+1; end < input.length; end++) {
sum += input[end];
bestSum = Math.max(sum, bestSum);
}
}
return bestSum;
}
/**
* Solves the maximum subarray sum in O(N^3) time. The two indices
* 'start' and 'end' iterate over all possible N^2 index pairs, and
* a third loop with index 'mid' iterates between them to compute
* the sum of input[start, end].
*/
public static int solve3(int[] input) {
int bestSum = -Integer.MAX_VALUE;
for (int start = 0; start < input.length; start++) {
for (int end = start; end < input.length; end++) {
// Compute the sum of input[start, end] using a third loop
// with index 'mid'. Update 'bestSum' if we found a new
// max subarray sum.
// Set the sum to initial input value to handle Edge case
// of all the values being negative.
int sum = input[start];
bestSum = Math.max(sum, bestSum);
for (int mid = start+1; mid < end; mid++) {
sum = Math.max(input[mid], input[mid] + sum);
bestSum = Math.max(sum, bestSum);
}
}
}
return bestSum;
}
public static void runTest(int[] input) {
System.out.printf("\n");
System.out.printf("Input: ");
for (int i = 0; i < input.length; i++) {
System.out.printf("%2d", input[i]);
if (i < input.length-1) {
System.out.printf(", ");
}
}
System.out.printf("\n");
int result = 0;
result = MaximumSubarraySum.solve1(input);
System.out.printf("solve1 result = %d\n", result);
result = MaximumSubarraySum.solve2(input);
System.out.printf("solve2 result = %d\n", result);
result = MaximumSubarraySum.solve3(input);
System.out.printf("solve3 result = %d\n", result);
}
public static void main(String argv[]) {
int[] test1 = { -2, -3, 4, -1, -2, -1, -5, -3 };
runTest(test1);
int[] test2 = { -2, -3, -4, -1, -2, -1, -5, 3 };
runTest(test2);
int[] test3 = { -2, -3, -4, -1, -2, -1, -5, -3 };
runTest(test3);
int[] test4 = { -2, -3, 4, -1, -2, 1, 5, -3 };
runTest(test4);
}
}
出力は次のとおりです。
Input: -2, -3, 4, -1, -2, -1, -5, -3
solve1 result = 4
solve2 result = 4
solve3 result = 4
Input: -2, -3, -4, -1, -2, -1, -5, 3
solve1 result = 3
solve2 result = 3
solve3 result = 3
Input: -2, -3, -4, -1, -2, -1, -5, -3
solve1 result = -1
solve2 result = -1
solve3 result = -1
Input: -2, -3, 4, -1, -2, 1, 5, -3
solve1 result = 7
solve2 result = 7
solve3 result = 7