最大子数组问题

本文探讨了求解最大子数组和问题的多种算法,包括暴力破解、动态规划和递归分治法。通过实例展示了不同算法的时间复杂度及优化过程。

问题描述

一个含有n个元素的整数数组,数组元素可以是正数也可以是负数,数组中连续的一个或多个元素称为改数组的子数组,子数组所有元素之和称为子数组和,求一个整数数组子数组和的最大值。例如数组array={1,2,4,8,5,6,7},相差就是{ 1,2,4,-3,1,1} 
最大子数组就是{1,2,4,8}
这里 以 int 类型 为例

 

有一组数{ 100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 79, 94, 90, 97 };

        /// <summary>
        /// 暴力破解
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        public int[] MaxOutCome(int[] array)
        {
            int[] mins = new int[array.Length - 1];

            int MaxIndex = 0;
            int MinIndex = 0;
            int Total = 0;
            for (int i = 0; i <array.Length-1; i++)//最后一次不用 没得减
            {
                mins[i] = array[i + 1] - array[i];
            }

            for (int i = 0; i < mins.Length; i++)//遍历下 差  数组
            {
                for (int j = i; j < mins.Length; j++)//从i 到length 依次遍历 0~L 1~L ....L-1~L;
                {
                    int temp = 0;
                    for (int k = i; k <=j; k++)//  从i 到 j 依次 累加  再 进行判断 和是否 比total 大   j也要加 进去 
                    {
                        temp += mins[k];
                    }
                    if (temp>Total)
                    {
                        Total = temp;
                        MaxIndex = j;
                        MinIndex = i;
                    }
                }
            }

            //遍历  结束 返回  下标
            return new int[] { MinIndex, MaxIndex+1 };//卖出 那一天 要 加上1 得到 从Minindex  到MaxIndex +1 之间   最大最大数组是[MinIndex,MaxIndex]
        }
  • 时间复杂度是 立方阶
  • 下面优化了一下 是平方阶
  •    static void MaxSubArray(int[] array)
            {
                int[] minValueArray = new int[array.Length - 1];
    
                for (int i = 0; i < array.Length-1; i++)
                {
                    minValueArray[i] = array[i + 1] - array[i];
                }
    
                int MaxValue = minValueArray[0];
                int endInex=0;
                int maxIndex=0;
                for (int i = 0; i < minValueArray.Length; i++)
                {
                    int temp =minValueArray[i];
                 
                    for (int j =i+1; j < minValueArray.Length; j++)
                    {                    
                        temp += minValueArray[j];
                        if (temp> MaxValue)
                        {
                            maxIndex = i;
                            MaxValue = temp;
                            endInex = j;
                        }
                    }                
                }
                Console.WriteLine(MaxValue + "开始位置:" + (maxIndex+1)+"结束位置:"+(endInex+1));
            }

     

递归 分治法

假设有数组 array   [min,max]

可以 用mid 进行 分区 

min       mid       max 

[min,max]

假设i是最大字数组的最小索引,j是最大索引

用 mid 进行分区

[min,mid]  [mid+1,hight]

分成两区间 

分3种情况 进行考虑

  • 1. i  j 都在 最小分区 [min,mid]
  • 2. i j 都在 最大分区[mid+1,max];
  • 3. i 在最小分区,j在 最大分区 [min,mid] 也是最坏情况

 

        /// <summary>
        /// 递归 分治 
        /// </summary>
        /// <param name="low"></param>
        /// <param name="high"></param>
        /// <param name="array"></param>
        /// <returns></returns>
        public MaxSubArray MaxSubArray2(int low,int high,int[] array)
        {
            //结束 条件
            if (low==high)
            {
                MaxSubArray maxSubArray;
                maxSubArray.startIndex = low;
                maxSubArray.endIndex = high;
                maxSubArray.total = array[low];
                return maxSubArray;
            }

            int mid = (low + high) / 2;//分区

            MaxSubArray subArray1 = MaxSubArray2(low, mid, array);//左边的     情况1
            MaxSubArray subArray2 = MaxSubArray2(mid+1,high, array);//右边的   情况2


            //   情况3
            // 左边 寻找
            int total = array[low];
            int startIndex = low;
            int temp = 0;
            for (int i = low; i <=mid; i++)
            {

                temp += array[i];
                if (temp>total)
                {
                    total = temp;
                    startIndex = i;
                }
            }

            //右边 寻找
            int total2 = array[mid + 1];
            int endIndex = mid + 1;
             temp = 0;
            for (int i = mid+1; i <high; i++)
            {
                total2 += array[i];
                if (temp>total2)
                {
                    total2 = temp;
                    endIndex = i;
                }
            }

            //   情况3
            MaxSubArray SubArray3;
            SubArray3.startIndex = startIndex;
            SubArray3.endIndex = endIndex;
            SubArray3.total = total + total2;

            if (subArray1.total > subArray2.total && subArray1.total > SubArray3.total)
            {
                return subArray1;
            }
            else if (subArray2.total > subArray1.total&&subArray2.total>SubArray3.total)
            {
                return subArray2;
            }
            else
            {
                return SubArray3;
            }


        }

类似的 动态规划算法:

最大连续子数组 问题 :

  最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

进阶:

如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。


解决思路1,用一次for遍历 用一个值来存储最大值,一个用来存储当前计算结果值, 如果这个结果值为负值,就从把结果清空,重新从nums[i]开始。


public int  MaxSerialArray( int[] nums)

{ 
    int max=nums[0];//默认 第一个位置初始值
    int tempMax=0;

   for(int i=0;i<nums.Length;i++)
    {
        if(temMax<=0)
        {
            //如果最大值已经是负数了,就从当前数开始  计算
           tempMax=nums[i];
        }else
        {
            tempMax+=nums[i];
        } 
        //负数直接不考虑,因为  一个负数 加上后,最小的肯定是以 这个负数为起始点,
        // 这点 理解 挺重/要的
        max=Mathf.Max(max,tempMax);
    }
return max;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值