最大子段和问题(动态规划)
一列数 { a 1 , a 2 , . . . , a n } \{a_1,a_2,...,a_n\} {a1,a2,...,an},求 Σ k = i j a k \Sigma_{k=i}^{j}a_k Σk=ijak的最大值,当最大值小于0时取0。即 m a x { 0 , m a x { Σ k = i j a k } } max\{0,max\{\Sigma_{k=i}^{j}a_k\}\} max{0,max{Σk=ijak}}。
- 一般方法
直接计算 1 < = i < = j < = n 1<=i<=j<=n 1<=i<=j<=n时所有情况的最大值。
int maxSubSum(int *a, int n, int& subidx_i, int& subidx_j)
{
int sum = 0;
for (int i = 0; i < n; i++)
{
for (int j = i; j < n; j++)
{
int temp_num = 0;
for (int k = i; k <= j; k++)
{
temp_num += a[k];
}
if (temp_num > sum)
{
sum = temp_num;
subidx_i = i;
subidx_j = j;
}
}
}
return sum;
}
- 一般方法改进
最内层循环出现重复计算,将其去掉。
int maxSubSum(int *a, int n, int& subidx_i, int& subidx_j)
{
int sum = 0;
for (int i = 0; i < n; i++)
{
int temp_num = 0;
for (int j = i; j < n; j++)
{
temp_num += a[j];
if (temp_num > sum)
{
sum = temp_num;
subidx_i = i;
subidx_j = j;
}
}
}
return sum;
}
- 分治算法
int maxsubsum(int *a, int begin, int end)
{
int sum = 0;
if (begin == end)
return a[begin] > 0 ? a[begin] : 0;
int middle = (begin + end) / 2;
int leftsubsum = maxsubsum(a, begin, middle);
int righsubsum = maxsubsum(a, middle + 1, end);
int left = 0, right = 0;
int temp_left = 0;
for (int i = middle; i >= begin; i--)
{
temp_left += a[i];
if (temp_left > left)
{
left = temp_left;
}
}
int temp_right = 0;
for (int i = middle + 1; i <= end; i++)
{
temp_right += a[i];
if (temp_right > right)
{
right = temp_right;
}
}
sum = left + right;
if (sum < leftsubsum)
sum = leftsubsum;
if (sum < righsubsum)
sum = righsubsum;
return sum;
}
int maxSubSum(int *a, int n)
{
return maxsubsum(a, 0, n - 1);
}
- 动态规划
int maxSubSum(int *a, int n)
{
int sum = 0, temp = 0;
for (int i = 0; i < n; i++)
{
if (temp > 0)
{
temp += a[i];
}
else
{
temp = a[i];
}
if (temp > sum)
{
sum = temp;
}
}
return sum;
}