要求:
给出一个数组,求出其中连续的,和最大的子序列
方法一 穷举
假定数组中有n个数字,将所有的可能列出来逐一比较取最大值
要进行n∗(n−1)2次的求和计算要进行\frac{n*(n-1)}{2} 次的求和计算 要进行2n∗(n−1)次的求和计算
C语言的实现
#include<stdio.h>
#include<limits.h>
int main()
{
int arr[] = {1,-2,3,4,-5, 6, -7, 6};
int sum = INT_MIN;
int i , j, k = sizeof(arr) / sizeof (arr[0]) ;
for(i = 0; i < k; i++)
{
int temp = 0;
for(j = i;j < k; j++)
{
temp += arr[j];
if (temp > sum)
{sum = temp;}
}
}
printf("%d",sum);
}
输出为 8
方法二 分治法
我们可以将该待处理的数组进行二分
该数组 int arr[] = {1,-2,3,4}可以从中间分开
拆分成
{1,-2} {3,4}
再次将两个子列拆分成
{1} {-2} {3} {4}
首先从{1}和{-2}进行处理,由于目的要求得到连续的子列,于是对{1,-2}这个子序列我们可以得到“1” “-2” “-1”这三种和,其中“-2”和“-1”是可以和后续的{3,4}进行相加的,而1要单独考虑是否大于后续的子集和
相比较方法一的穷举用时与n²成正比。使用分治方法所处理的时间和nlogn成正比
C语言代码实现
#include<stdio.h>
int divide(int arr[],int L,int R)
{
if(L == R){return arr[L];}//只有一个数的话最大值只能是他本身
int mid = (L + R) / 2;
int L_max = divide(arr, L, mid);//在mid左半部最大的子列
int R_max = divide(arr, mid + 1, R);//右半部最大子列
int i,L_sum = 0, L_temp = 0;
for(i = mid; i >= L; i--)//与mid有联系的左半部分求和
{
L_sum += arr[i];
if(L_sum > L_temp) L_temp = L_sum;
}
int R_sum = 0, R_temp = 0;
for(i = mid + 1; i <= R; i++)//右半部分
{
R_sum += arr[i];
if(R_sum >= R_temp) R_temp = R_sum;
}
int A_sum = R_temp + L_temp;//与mid有关的最大子列
if(A_sum > L_max && A_sum > R_max){return A_sum;}
else if(L_max > A_sum && L_max > R_max){return L_max;}
else return R_max;
}
int main()
{
int arr[] = {1,-2,3,4,-5, 6, -7, 6};
int sum = INT_MIN;
int i , j, k = sizeof(arr) / sizeof (arr[0]) ;
printf("%d",divide(arr,0,k-1));//注意在进行递归的时候R的大小可能会越界,所以要减一
}
方法三 动态规划法
开两块区域
由于我们要连续的,加起来和最大的子列
那么假定第n个数字是3,前面n-1个数字的和却是一个负数,那么我们自然是没有加前面n-1个数字的必要的。
同时我们假定前n-1项中,已经找到了一个子列,和为5,这样子我们就可以从第n项开始继续往后加来寻找是否可能存在一个新的子列和可以大于5
第一个区域用于储存第 i 项到第 j 项之间的和,当 i 到 j 的项的和变为负数的时候,i = j +1; j 继续增大,然后继续储存 i 到 j 之间的整数和
然后对 每次进行依次区域1储存后的最大值和区域二已有的最大值进行比较,取两者中较大值继续储存在区域二中(也就是说区域二是一个一直不递减的数列)
C语言代码实现
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int dynamic(int arr[], int L, int R)
{
int *p1 = (int *)malloc(sizeof(int) * R);
int *p2 = (int *)malloc(sizeof(int) * R);
memset(p1,0,sizeof(int)*R);
memset(p2,0,sizeof(int)*R);
*p1 = arr[L];
*p2 = arr[L];
int temp = *p1, i;
for(i = L + 1; i < R; i++)
{
temp += arr[i];
p1[i] = (temp > 0) ? temp : p1[i - 1];
p2[i] = (p1[i] > p2[i - 1]) ? p1[i] : p2[i - 1];
if (temp < 0) temp = 0;
}
return p2[R - 1];//注意越界问题
}
int main()
{
int arr[] = {1,-2,3,4,-5, 6, -7, 6};
int k = sizeof(arr) / sizeof (arr[0]) ;
printf("%d",dynamic(arr,0,k));/
}
本文对比了三种求解数组中连续子序列和最大值的方法:穷举法、分治法(递归实现)和动态规划。穷举法计算复杂度高,分治法时间复杂度为nlogn,而动态规划通过存储和更新子问题结果,效率提升。通过C语言实例演示了每种方法的代码实现。

1904

被折叠的 条评论
为什么被折叠?



