算法导论实践——最大连续子序列

算法导论实践——最大连续子序列(LeetCode 53题)

很巧妙的算法,没有看参考思路的话自己应该想不出来。之前觉得不用分治递归无论如何都需要O(n2)的时间复杂度(想要应用动态规划,但却不知道怎么用,脑子里却死活都是二维定义M[i,j]之类的 ),就算是教材上的分治递归也需要O(nlogn)。经过高人指点后,不得不赞扬算法的神奇。

理论

算法关键:(设M[i]为以i结尾的连续最大子数组的和)

  • 最优子结构
    将代表M[i]的连续最大子数组用k = i - 1划分后,M[i] = Max{M[i-1]+A[i],A[i]}这里M[i-1]是以i-1结尾的连续最大子数组,如果说M[i-1]+A[i]大于A[i],这也就是说,A[i]可以加入前一个子数组如果M[i-1]+A[i]小于A[i],这也就是说,A[i]就应该等于M[i],A[i]本身就是以i结尾的连续最大子数组
    (小于的情况可以用反证法予以论证)
    设A[k,i-1]是M[i-1]所代表的最大连续子数组,且M[i]所对应的连续最大子数组为A[j……k……i-1,i],下面证明矛盾。因为A[k,i-1]是A[1,i-1]的最大连续子数组,因此A[j……k……i-1]的和小于A[k,i-1],因此A[j……k……i-1,i]的和小于A[k……i-1,i],而又M[i-1]+A[i]小于A[i],因此A[k……i-1,i]小于A[i],所以A[i]是最大连续子数组,M[i]就应该等于A[i]这样,与M[i]所对应的连续最大子数组为A[j……k……i-1,i]假设相反,故证明矛盾。根据论证知,此时M[i] = A[i]

  • 重叠子问题
    以[1,2,3]为例易得。

  • 代价方程

M[i] = A[i]i == 0
M[i] = MAX{(M[i - 1] + A[i]), A[i]}if i > 0
  • 构造最优解
    遍历M,找到最大解即最优解
  • 时间复杂度分析
    • 代价:
      只需遍历数组A
    • 构造最优解:
      只需遍历数组M
    • 总时间复杂度为O(n)

实践

BigMaxSubArray.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace BigInteger
{
    public static class BigMaxSubArray
    {

        /*
         * 演算:
         * (设M[i]为以i结尾的连续最大子数组的和)
         * 
         * 最优子结构
         *  将代表M[i]的连续最大子数组用k = i - 1将数组划分后,M[i] = Max{M[i-1]+A[i],A[i]}
         *  这里M[i-1]是以i-1结尾的连续最大子数组,如果说M[i-1]+A[i]大于A[i],这也就是说,A[i]可以加入前一个子数组
         *  如果M[i-1]+A[i]小于A[i],这也就是说,A[i]就应该等于M[i],A[i]本身就是以i结尾的连续最大子数组
         * 
         * (小于的情况可以用反证法予以论证)
         *      设A[k,i-1]是M[i-1]所代表的最大连续子数组,且M[i]所对应的连续最大子数组为A[j……k……i-1,i],下面证明矛盾。
         *      因为A[k,i-1]是A[1,i-1]的最大连续子数组,因此A[j……k……i-1]的和小于A[k,i-1],因此A[j……k……i-1,i]的和
         *      小于A[k……i-1,i],而又M[i-1]+A[i]小于A[i],因此A[k……i-1,i]小于A[i],所以A[i]是最大连续子数组,M[i]就应该等于A[i]
         *      这样,与M[i]所对应的连续最大子数组为A[j……k……i-1,i]假设相反,故证明矛盾。根据论证知,此时M[i] = A[i]
         * 
         *  
         *  
         *  
         * 重叠子问题(以[1,2,3]为例)
         *                      (1 2 3)
         *  (1)(2)(3)(1 + 2)(2 + 3)(1 + 2 + 3)
         *                               (1 + 2)    (2 + 3)
         * 
         * 代价:
         *
         *       M[i] = A[i]                                  if i == 0  
         *       M[i] = MAX{(M[i - 1] + A[i]), A[i]}          if i > 0
         *  
         * 代价保存:
         *       M这个一维数组中
         *  
         * 构造优化解:
         *       遍历M,找到最大解即最优解
         *       
         * 时间复杂度分析:
         *       代价:
         *          只需遍历数组A
         *          
         *       构造最优解:
         *          只需遍历数组M
         *          
         *       总时间复杂度为O(n)
         */
        private const int MAX_ARRAYNUM = 10;
        private static int[] M = new int[MAX_ARRAYNUM];

        public static int[] MaxSubArray(int[] A)
        {
            for(int i = 0; i < A.Length; i++)
            {
                if (i == 0)
                {
                    M[i] = A[i];
                }
                else
                {
                    M[i] = Math.Max(M[i - 1] + A[i], A[i]);
                }
            }

            return M;
        } 

        

    }

}

Program.cs

using System;
using BigInteger;
using System.Linq;

namespace BigInteger
{
    class Program
    {
        static void Main(string[] args)
        {

            //int[] A = { 11, 12, 14, 13, 15, 5, 6, 7, 8, 9, 1, 2, 3, 4, 10, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };
            //int Element = BigDataMedianUtil.Select_i_th_Data(A, 0, A.Length - 1, A.Length/2);
            //Console.WriteLine(Element);
            int[] A = { -2, 1, -3, 4, -1, 2, 1, -5, 4 };//LeetCode 53题上的示例
            int[] M = BigMaxSubArray.MaxSubArray(A);
            Console.WriteLine(M.Max());
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值