一、问题描述
最大和连续子数组(maximum subarray):目的是为了在一维数字数组中找到最大的连续子数组的和。
如下图所示
这个问题可以使用几种不同的算法技术来解决,包括暴力、分而治之、动态规划、减少到最短路径等,我们这里主要关注动态规划算法。
二、算法示例
对于下面给出的数组,总和最大的连续子数组是 [4, -1, 2, 1],总和为 6。我们将使用这个数组作为本文其余部分的示例。
1、暴力算法
Java参考代码如下
public int FindSubarrayByViolence(int[] array) {
int n = array.length;
int MaxSum = array[0];
for(int i = 0 ; i < n ; i ++){
int temp = 0;
for(int j = i; j < n ; j ++ ){
temp += array[j];
MaxSum = MaxSum > temp ? MaxSum : temp;
}
}
return MaxSum;
}
如果数组的大小是n,那么这个解决方案的时间复杂度是O(n²)。
2、Kadane算法
Kadane算法使用最优子结构的方式(在每个位置结束的最大子数组是从一个相关但较小且重叠的子问题中以简单的方式计算出来的:在前一个位置结束的最大子数组)这个算法可以被视为一个简单的例子的动态规划。Kadane算法能够在运行时间为O(n)的数组中找到连续子数组的最大和。
伪代码描述如下
初始化:
max_so_far = INT_MIN
max_ending_here = 0
循环数组的每个元素
(a) max_ending_here = max_ending_here + a[i]
(b) if(max_so_far < max_ending_here)
max_so_far = max_ending_here
(c) if(max_ending_here < 0)
max_ending_here = 0
返回 max_so_far
Kadane 算法的简单思想是寻找数组的所有正连续段(max_ending_here 用于此)。并跟踪所有正段之间的最大和连续段(max_so_far 用于此)。每次我们得到一个正和时,将其与 max_so_far 进行比较,如果它大于 max_so_far 则更新 max_so_far 。
(1)Java参考代码1
import java.io.*;
import java.util.*;
class Kadane
{
public static void main (String[] args)
{
int [] a = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
System.out.println("Maximum contiguous sum is " +
maxSubArraySum(a));
}
static int maxSubArraySum(int a[])
{
int size = a.length;
int max_so_far = Integer.MIN_VALUE, max_ending_here = 0;
for (int i = 0; i < size; i++)
{
max_ending_here = max_ending_here + a[i];
if (max_so_far < max_ending_here)
max_so_far = max_ending_here;
if (max_ending_here < 0)
max_ending_here = 0;
}
return max_so_far;
}
}
(2)Java参考代码2
import java.io.*;
class GFG {
static int maxSubArraySum(int a[], int size)
{
int max_so_far = a[0];
int curr_max = a[0];
for (int i = 1; i < size; i++)
{
curr_max = Math.max(a[i], curr_max+a[i]);
max_so_far = Math.max(max_so_far, curr_max);
}
return max_so_far;
}
public static void main(String[] args)
{
int a[] = {-2, -3, 4, -1, -2, 1, 5, -3};
int n = a.length;
int max_sum = maxSubArraySum(a, n);
System.out.println("Maximum contiguous sum is " + max_sum);
}
}
(3)Java参考代码3,获取起止索引
class Temp {
static void maxSubArraySum(int a[], int size)
{
int max_so_far = Integer.MIN_VALUE,
max_ending_here = 0,start = 0,
end = 0, s = 0;
for (int i = 0; i < size; i++)
{
max_ending_here += a[i];
if (max_so_far < max_ending_here)
{
max_so_far = max_ending_here;
start = s;
end = i;
}
if (max_ending_here < 0)
{
max_ending_here = 0;
s = i + 1;
}
}
System.out.println("Maximum contiguous sum is " + max_so_far);
System.out.println("Starting index " + start);
System.out.println("Ending index " + end);
}
public static void main(String[] args)
{
int a[] = { -2, -3, 4, -1, -2, 1, 5, -3 };
int n = a.length;
maxSubArraySum(a, n);
}
}