您的位置:首页 > 其它

经典 - 最大和/最大积连续子序列问题

2011-05-26 00:06 316 查看
原文:
http://fayaa.com/tiku/view/56/




对于一个包含了正负整数的数组,求其“最大和”连续子序列 以及 “最大积”连续子序列

比如:

3 -4 8 -5 2 6 -7

最大和子序列是:8 -5 2 6,和为11

最大积子序列是:3 -4 8 -5 2 6,积自己算:)





对于最大和问题:

我们令F(n)表示[0,n]区间内以d
为结尾的最大和,d为原序列,那么有:

F(n + 1) = Max{d[n + 1],F(n) + d[n + 1]} = d[n + 1] + Max{0, F(n)}

对于最大积问题:

由于负数的存在,我们不能简简单单只存一个当前最大值,我们还需要存当前最小值。

我们令F(n)表示[0,n]区间内以d
为结尾的最大积,令G(n)表示[0,n]区间内以d
为结尾的最小积,d为原序列,那么有:

F(n + 1) = Max{F(n) * d[n + 1], d[n + 1], G(n) * d[n + 1]}

G(n + 1) = Min{F(n) * d[n + 1], d[n + 1], G(n) * d[n + 1]}

代码如下:



using System;
public class FayaaView56
{
    /// <summary>
    /// 求解最大子段和,返回结果以及最优解的始末下标
    /// </summary>
    /// <param name="seq">输入序列</param>
    /// <param name="beginIndex">返回最优解的起始下标</param>
    /// <param name="endIndex">返回最优解的结束下标</param>
    /// <returns>最大子段和</returns>
    public static int MaxSubSum(int[] seq, out int beginIndex, out int endIndex)
    {
        if (seq == null || seq.Length == 0)
            throw new ArgumentNullException("输入序列不能为空");
        int bestResult = seq[0];
        beginIndex = endIndex = 0;
        int curSum = seq[0], curBeginIndex = 0;
        for (int i = 1; i < seq.Length; i++)
        {
            if (curSum > 0)
            {
                curSum += seq[i];
            }
            else
            {
                curSum = seq[i];
                curBeginIndex = i;
            }
            if (curSum > bestResult)
            {
                bestResult = curSum;
                beginIndex = curBeginIndex;
                endIndex = i;
            }
        }
        return bestResult;
    }
    /// <summary>
    /// 求解最大子段积,返回结果以及最优解的始末下标
    /// </summary>
    /// <param name="seq">输入序列</param>
    /// <param name="beginIndex">返回最优解的起始下标</param>
    /// <param name="endIndex">返回最优解的结束下标</param>
    /// <returns>最大子段积</returns>
    public static long MaxSubMul(int[] seq, out int beginIndex, out int endIndex)
    {
        if (seq == null || seq.Length == 0)
            throw new ArgumentNullException("输入序列不能为空");
        long maxMul = seq[0];
        beginIndex = endIndex = 0;
        long curMaxMul = seq[0], curMinMul = seq[0];
        int curMinBeginIndex = 0, curMaxBeginIndex = 0;
        for (int i = 1; i < seq.Length; i++)
        {
            long a = curMaxMul * seq[i], b = curMinMul * seq[i];
            long max, min;
            int tmpMaxBeginIndex, tmpMinBeginIndex;
            if(a > b)
            {
                max = a;
                min = b;
                tmpMaxBeginIndex = curMaxBeginIndex;
                tmpMinBeginIndex = curMinBeginIndex;
            }
            else
            {
                max = b;
                min = a;
                tmpMaxBeginIndex = curMinBeginIndex;
                tmpMinBeginIndex = curMaxBeginIndex;
            }
            if (seq[i] > max)
            {
                curMaxBeginIndex = i;
                curMaxMul = seq[i];
            }
            else
            {
                curMaxBeginIndex = tmpMaxBeginIndex;
                curMaxMul = max;
            }
            if (seq[i] < min)
            {
                curMinBeginIndex = i;
                curMinMul = seq[i];
            }
            else
            {
                curMinBeginIndex = tmpMinBeginIndex;
                curMinMul = min;
            }
            if (curMaxMul > maxMul)
            {
                maxMul = curMaxMul;
                beginIndex = curMaxBeginIndex;
                endIndex = i;
            }
        }
        return maxMul;
    }
    public static void Main()
    {
        int[] seq = { 3, -4, 8, -5, 2, 6, -7};
        int beginIndex, endIndex;
        Console.WriteLine("最大子段和结果为:");
        Console.WriteLine(MaxSubSum (seq, out beginIndex, out endIndex));
        Console.WriteLine("最优序列为:");
        for (int i = beginIndex; i <= endIndex; i++)
        {
            Console.Write(seq[i] + " ");
        }
        Console.WriteLine();
        Console.WriteLine("最大子段积结果为:");
        Console.WriteLine(MaxSubMul(seq, out beginIndex, out endIndex));
        Console.WriteLine("最优序列为:");
        for (int i = beginIndex; i <= endIndex; i++)
        {
            Console.Write(seq[i] + " ");
        }
        Console.WriteLine();
    }
}





最大子段和结果为:

11

最优序列为:

8 -5 2 6

最大子段积结果为:

5760

最优序列为:

3 -4 8 -5 2 6
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: