zoukankan      html  css  js  c++  java
  • 最大子序列问题及其求解C 语言学习

    这两天看了看最大子序列问题,顺便的做一下笔记,最大子序列问题相信大家都再熟悉不过了,来回顾一下问题:

    给定整数clip_image002[6](可能有负数),求clip_image002[8]的最大值(为方便起见,如果所有整数均为负数,则最大子序列和为 0 )。

    下面来看三种实现方法:

    1,使用两层 for 循环,算法复杂度显然是 O(N²):

    int MaxSubSequenceSum(const int A[], int N)
    {
    	int ThisSum, MaxSum, i, j;
    	MaxSum = 0;
    	for(i = 0; i < N; i ++)//外层的 for 循环
    	{
    		ThisSum = 0;
    		for(j = i; j < N; j ++)//内层的 for 循环
    		{
    			ThisSum += A[j];
    			if(ThisSum > MaxSum)
    				MaxSum = ThisSum;
    		}
    	}
    	return MaxSum;
    }

    这种方法似乎是我们最先想到的解决办法,当然也很好理解。

    2,使用“分治(divide-and-conquer)”的策略,其想法是把问题分成两个大致相等的子问题,然后递归的对它们进行求解,其算法复杂度是 O(N logN):

    为了便于理解,再来解释一下这种方法:在我们的例子当中,最大子序列和可能出现在三处,或者整个出现在输入数据的左半部,或者整个出现在右半部,或者跨越输入数据的中部从而占据左右两半部分。前两种情况可以递归地进行求解,第三种情况的最大和可以通过求出前半部分的最大和(包含前半部分的最后一个元素)以及后半部分的最大和(包含后半部分的第一个元素)而得到。然后将这两个和加在一起。作为一个例子,考虑如下的输入:

    -------------------------
     前半部分    |     后半部分
    -------------------------
     4 -3 5 -2     -1 2 6 -2
    -------------------------

    其中前半部分的最大子序列和为 6(A1 –> A3),后半部分的最大子序列和为 8 (A6 –> A7)。

    前半部分包含最后一个元素的最大和为 4 (A1 –> A4),后半部分包含其第一个元素的最大和为 7 (A5 –> A7)。因此,横跨这两部分且通过中间的最大和为 4 + 7 = 11 (A1 –> A7)。

    于是,答案为 11。再来看看实现代码:

    //主函数
    static int MaxSubSum(const int A[], int Left, int Right)
    {
    	int MaxLeftSum, MaxRightSum;
    	int MaxLeftBorderSum, MaxRightBorderSum;
    	int LeftBorderSum, RightBorderSum;
    	int Center, i;
    	
    	if(Left == Right) /*基准情况*/
    		if(A[Left] > 0)
    			return A[Left];
    		else
    			return 0;
    	
    	/*处理递归*/
    	Center = (Left + Right) / 2;
    	MaxLeftSum = MaxSubSum(A, Left, Center);
    	MaxRightSum = MaxSubSum(A, Center + 1, Right);
    	
    	MaxLeftBorderSum = 0;LeftBorderSum = 0;
    	for(i = Center; i >= Left; i --)
    	{
    		LeftBorderSum += A[i];
    		if(LeftBorderSum > MaxLeftBorderSum)
    			MaxLeftBorderSum = LeftBorderSum;
    	}
    	
    	MaxRightBorderSum = 0;RightBorderSum = 0;
    	for(i = Center + 1; i <= Right; i ++)
    	{
    		RightBorderSum += A[i];
    		if(RightBorderSum > MaxRightBorderSum)
    			MaxRightBorderSum = RightBorderSum;
    	}
    	//处理完毕,找出和最大的一个子序列
    	return Max3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);
    }
    //调用函数
    int MaxSubSequenceSum(const int A[], int N)
    {
    	return MaxSubSum(A, 0, N - 1);
    }
    //比较函数
    int Max3(int x, int y, int z)
    {
    	return (((x > y)?x:y) > z)?((x > y)?x:y):z;
    }

    3,使用一次 for 循环,算法复杂度为 O(N):

    这个算法乍看上去不是很好理解,不过它的效率却是这三个当中最高的一个,仔细地琢磨的话会理解这个神奇的算法的:

    int MaxSubSequenceSum(const int A[], int N)
    {
    	int ThisSum, MaxSum, j;
    	ThisSum = MaxSum = 0;
    	for(j = 0; j < N; j ++)
    	{
    		ThisSum += A[j];
    		if(ThisSum > MaxSum)
    			MaxSum = ThisSum;
    		else if(ThisSum < 0)
    			ThisSum = 0;
    	}
    	return MaxSum;
    }
  • 相关阅读:
    BZOJ1077 并查集
    linux(fedora) 第三课
    hdu 4513 吉哥系列故事——完美队形II(manacher)
    hdu 3294 Girls' research(manacher)
    FZU
    蓝桥杯试题 k倍区间(dp)
    蓝桥杯 带分数(全排列+枚举)
    天梯赛 L2-001 紧急救援
    蓝桥杯[2017年第八届真题]分考场 (图着色问题)
    hdu 3068 最长回文(manacher)
  • 原文地址:https://www.cnblogs.com/catprayer/p/1856230.html
Copyright © 2011-2022 走看看