数组连续子序列的最大的和-四种算法,四种时间复杂度

给定一组数据:31, -41, 59, 26, -53, 58, 97, -93, -23, 84。要求找到这组数据中连和最大的子序列,相信很多人都看过这个算法,能够直接给出线性时间复杂度的解法。但是还是有其他解法的,而且是循序渐进的,从O(n^3), O(n^2), O(n*logn)到O(n)。

在开始算法之前要进行一下约定,如果当前输入的都是负数的时候,综合最大的子序列是空的,总和为0.

第一种方法就是brute-force解法,就是对满足所有的0<=i < j < n的组合(i,j)进行迭代,对于每个整数对都要计算a[i,j]的总和,这个算法有个特点,也就是造成时间复杂度很高的缺点,对于每次计算的结果没有记录,只是简单的将此次计算的结果和上次计算的结果进行比较,求得当前最大值后,就给扔掉了。下面给出算法:

current_max = 0;
sum = 0;
for(i = 0; i < n; i++) {
	for(j = i; j < n; j++) {
		sum = 0;
		for(k = i; k <= j; k++)
			sum += a[k];
		if(sum > current_max)
			current_max = sum;
	}
}


很清楚的可以看出,对i和j的操作过程中,只是对当前和与上次的和做简单的比较,之后就扔弃了。想一想,可不可以这样做,对于特定的i,遍历所有可行的j值,记录此次(i,j)的操作,对于(i,j+1)的操作可以在(i,j)所得和的基础上简单的加a[j+1]就可以了。

下面给出算法:

current_max = 0;
for(i = 0; i < n; i++) {
	sum = 0;
	for(j = i; j < n; j++) {
		sum += a[j];
		if(sum > current_max)
			current_max = sum;
	}
}
这个时间复杂度比上次的有所降低。

同时,这个问题还可以用分治算法来解决,可能会有疑问,因为分治算法是用来解决子问题之间没有联系的问题的。而求连续子序列和最大值得问题更多的和动态规划相关,因为用动态规划很容易解决这个问题。但是分治也可以,这种算法很巧妙,巧妙的让人不可思议。给出算法代码:

#include<stdio.h>
int max(int a, int b, int c) {
	if(a > b) {
		if(a > c) {
			return a;
		} else {
			return c;
		}
	} else {
		if(b > c) {
			return b;
		} else {
			return c;
		}
	}
}
int get_max(int *a, int low, int high) {
	int m = (low + high) / 2;
	int i;
	int sum, lmax, rmax;

	if(low > high)
		return 0;
	if(low == high)
		return a[low] > 0 ? a[low] : 0;

	sum = lmax = 0;
	for(i = m; i >= low; i--){
		sum += a[i];
		if(sum > lmax) {
			lmax = sum;
		}
	}
	
	sum = rmax = 0;
	for(i = m + 1; i <= high; i++) {
		sum += a[i];
		if(sum > rmax) {
			rmax = sum;
		}
	}

	return max(lmax + rmax, get_max(a, low, m), get_max(a, m + 1, high));
}

void main() {
	int a[] = {31, -41, 59, 26, -53, 58, 97, -93, -23, 84};
	int n = sizeof(a) / sizeof(int);
	int result = get_max(a, 0, n - 1);
	printf("max_sum = %d\n", result);
}
这个算法的巧妙之处就在于计算lmax和rmax之处,计算lmax是从m开始到low结束,计算rmax是从m+1开始,在high结束。

最后一种方法就是使用动态规划了,相信很多人能给出此种算法。直接给出代码:

#include<stdio.h>
int get_max2(int *a, int n) {
	int current_max = a[0];
	int final_max = a[0];
	int i;
	for(i = 1; i < n; i++) {
		if(current_max + a[i] > 0) {
			current_max += a[i];
		} else {
			current_max = 0;
		}
		if(current_max > final_max) {
			final_max = current_max;
		}
	}
	return final_max;
}
void main() {
	int a[] = {31, -41, 59, 26, -53, 58, 97, -93, -23, 84};
	int n = sizeof(a) / sizeof(int);
	int rst = get_max2(a, n);
	printf("max_sum = %d\n", rst);
}



你可能感兴趣的:(数组连续子序列的最大的和-四种算法,四种时间复杂度)