最大和连续子串

风流意气都作罢 提交于 2020-11-21 05:44:16

一、问题描述

输入一组整数,求出这个整数数组最大和的连续子串。例如,整数数组为{4, -2, 59, -45, 4},最大和的连续子串为{4, -2, 59},最大和为61。需要注意的是要求子串连续,另外,子串的长度可以是1.

这个也是曾经出过的一道面试提,最早是浙大的一道考研算法设计题。

二、问题分析

第一种方法。最简单的思路就是用两层循环来解决问题。外面一层是从1到整数数组的长度,里面的那层循环是当前的位置加1一直到整数数组的结束,里面的循环来算所有的和。换句话说就是,内层循环每次从i+1开始到字符数组结束的和,这些和是numbers[i]+numbers[i+1],numbers[i]+numbers[i+1]+numbers[i+2],...,numbers[i]+...+numbers[length(numbers)]中找到最大的那个。外层循环则是找到全局最大的那个。这个方法比较好想,只给出伪代码,这个的时间复杂度为:

下面是伪代码:

for i = 0 to length(numbers)
   current = numbers[i]
   for j = i + 1 to length(numbers)
      current += numbers[j]
      if(current_max < current)
         current_max = current
    end
    if(max < current_max)
    max = current_max
end
第二种思路可以设置一个变量current_max来保存当前作出的最大和,用一个变量max来保存全局的最大和。当加到一个负数时,当前和会减少,但是,是不是会不会改变全局最大和还需要看后面的一个元素。而如果当前的current_max变为负数了,说明如果再用这个数加后面的数只会使和变小,所以把current_max赋值为0,但是需要额外考虑的就是数组全为负数的情况。用这种方法可以把时间复杂度降到O(n)。


第三种思路可以考虑动态规划的方法,但是用动态规划解决问题的思路我还没有弄的太明白,等弄明白后在补充到这里。

三、程序实现

#include <stdio.h>
#include <stdlib.h>

#define MAX(a, b) ((a)>(b)?(a):(b))

int main(int argc, char const *argv[])
{
	int n,
		i,
		current_max,
		max;
	int* numbers;

	printf("Please input the integer n(n > 0):\n");
	while(EOF != (scanf("%d", &n)))
	{
		numbers = (int*)malloc(n * sizeof(int));
		i = 0;

		while(i++ < n)
			scanf("%d", &numbers[i - 1]);

		printf("The computing numbers are : %d", numbers[0]);
		for(i = 1; i < n; i++)
			printf(",%d", numbers[i]);
		printf("\n");

		current_max = numbers[0];
		max = current_max;

		for(i = 1; i < n; i++)
		{
			current_max += numbers[i];
			max = MAX(max, current_max);
			max = MAX(max, numbers[i]);

			if(0 > current_max)
			{
				if((i + 1) != (n - 1))
					current_max = 0;
				else
					current_max = numbers[i];
			}
		}

		printf("the restult is : %d\n", max);

		free(numbers);

		printf("Please input the integer n(n > 0):\n");
	}

	return 0;
}
看计算时的那个for循环,我的思路是先进行相加在考虑是否改变current_max和max,还有一种思路是 考虑利用上一次current_max的值来判断对current_max操作,即求和或者赋值为当前数组元素的值,之后在设置全局最大值max(见参考文献1),这里给出这种情况求和的伪代码:


max=numbers[0];       
current_max=0;  
for(i=0;i<n;i++)  
{  
    if(current_max>=0)   
        current_max+=numbers[i];  
    else     
        current_max=numbers[i];  
    if(current_max>max)  
        max=current_max;  
}

四、测试结果

我把上面两种方法(第一种是先求和在判断是否改变current_max,第二种是根据前一次的current_max来判断这次是否需要求和还是赋值current_max为当前的整数数组元素)。

第一组测试数据(只有一个数)如下图:

第二组测试数据(一负一正)如下图:

第三组测试数据(全负)如下图:

第四组测试数据(正负都有)如下图:

五、参考资料

1. 程序员编程艺术:第七章、求连续子数组的最大和:

http://blog.csdn.net/v_JULY_v/article/details/6444021


说明:

如有错误还请各位指正,欢迎大家一起讨论给出指导。

上述程序完整代码的下载链接:

https://github.com/zeliliu/BlogPrograms/tree/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%26%E7%AE%97%E6%B3%95/max%20sum%20of%20continuous%20substring

最后更新时间:2013-05-07

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!