最大子序列和问题

最近在看数据结构与算法分析这本书。书中第一章描述了这样一个问题:输入一组整数,求出这组数字子序列和中最大值。

例如:1、序列:-2 11 -4 13 -5 -2,则最大子序列和为20。

    2、序列:-6 2 4 -7 5 3 2 -1 6 -9 10 -2,则最大子序列和为16。


  算法一:使用穷举法计算每个子序列和,从中获得最大值。这个想法是最简单,它的时间复杂度为O(N^3)。在处理小数据量的时候不会有很大的影响,但是在处理大数量的时候,将要花费大量的时间。

	public static int MaxSubsequenceSum_1(int[] a)
        {
            int N = a.Length;
            int MaxNum;
            MaxNum = 0;
            for (int i = 0; i < N; i++)
            {
                for (int j = i; j < N; j++)
                {
                    int ThisNum;
                    ThisNum = 0;
                    for (int k = i; k < j; k++)
                    {
                        ThisNum += a[k];
                    }
                    if (ThisNum > MaxNum)
                    {
                        MaxNum = ThisNum;
                    }  
                }
            }
            return MaxNum;
        }
算法二:通过对算法一的研究可以发现,算法一可以进行优化。如算法二所示。跟算法一进行对比,算法二的时间复杂度为O(N^2)。该算法是计算N轮,每轮以不同的起点数进行计算,获得以该起点数最大的子序列和

        public static int MaxSubsequenceSum_2(int[] a)
        {
            int N = a.Length;
            int MaxNum = 0;

            for (int i = 0; i < N; i++)
            {
                int ThisNum = 0;
                for (int j = i; j < N; j++)
                {
                    ThisNum += a[j];
                    if (ThisNum > MaxNum)
                    {
                        MaxNum = ThisNum;
                    }
                }
            }

            return MaxNum;
        }
算法三:通过对最大子序列和问题的分析,我们可以得到结论:一个负数不可能成为一最大子序列的起点,一个子序列和为负数他也不可能成为最大子序列的前缀。因此,我们可以得到算法三,时间复杂度为O(N)。

	public static int MaxSubsequenceSum_3(int[] a)
        {
            int N = a.Length;
            int ThisNum, MaxNum;
            ThisNum = 0;
            MaxNum = 0;
            for (int i = 0; i < N; i++)
            {
                ThisNum += a[i];
                if (ThisNum > MaxNum)
                    MaxNum = ThisNum;
                else if (ThisNum < 0)
                    ThisNum = 0;
            }
            return MaxNum;
        }
算法四:计算机编程算法中有一个重要的策略是“分治策略”。该策略的思想是:将一个大问题分解成若干个与原问题形式相同的小问题。通过解决这些小问题,从而将原来的大问题得以解决。最大子序列和这个问题也可以采用该策略进行处理。

针对最大子序列和这个问题,我们发现:最大子序列可能在三个地方出现,或者在左半部,或者在右半部,或者跨越输入数据的中部而占据左右两部分。前两种情况递归求解,第三种情况的最大和可以通过求出前半部分最大和(包含前半部分最后一个元素)以及后半部分最大和(包含后半部分的第一个元素)相加而得到。该算法的时间复杂度为O(NlogN)。

        public static int MaxSubsequenceSum_4(int[] a, int left, int right)
        {
            if (left == right)
            {
                if (a[left] > 0)
                {
                    return a[left];
                }
                else
                    return 0;
            }
            else
            {
                int MaxLeftNum, MaxRightNum;
                int Center = (left + right) / 2;
                MaxLeftNum = MaxSubsequenceSum_3(a,left,Center);
                MaxRightNum =MaxSubsequenceSum_3(a,Center+1,right);
                int LeftBorderNum, RightBorderNum;
                LeftBorderNum = 0;
                RightBorderNum = 0;
                int MaxLeftBorderNum, MaxRightBorderNum;
                MaxRightBorderNum = 0;
                MaxLeftBorderNum = 0;

                for (int i = Center; i >= left; i--)
                {
                    LeftBorderNum += a[i];
                    if (LeftBorderNum > MaxLeftBorderNum)
                    {
                        MaxLeftBorderNum = LeftBorderNum;
                    }
                }

                for (int j = Center+1; j <= right; j++)
                {
                    RightBorderNum += a[j];
                    if (RightBorderNum > MaxRightBorderNum)
                    {
                        MaxRightBorderNum=RightBorderNum;
                    }
                }

                return Math.Max(Math.Max(MaxRightNum, MaxLeftNum), MaxRightBorderNum + MaxLeftBorderNum);
            }
        }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值