编程内功修炼之分治算法——最大子数组问题详解

版权声明:本文为博主原创文章,欢迎各位转载,但须注明出处 https://blog.csdn.net/qq_34202873/article/details/87975494

分治算法 - 最大子数组问题

分治策略是:对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。这种算法设计策略叫做分治法。简单来说就是把一个大问题分成多个小问题去解决。采用递归的方式。

股票问题

在这里插入图片描述

如上图,求解在哪天买入以及哪天卖出能赚到最多钱。

此题有两种解法:

1. 暴力破解,但是数量一大执行效率可想而知
        static void Main(string[] args)
        {
            int[] priceArray = { 100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 79, 94, 90, 97 };
            int[] priceFluctuationArray = new int[priceArray.Length-1];//价格波动的数组
            for (int i = 1; i < priceArray.Length; i++)
            {
                priceFluctuationArray[i - 1] = priceArray[i] - priceArray[i - 1];
            }
            int total = priceFluctuationArray[0];//默认数组的第一个元素 是最大子数组
            int startIndex = 0;
            int endIndex = 0;
            for (int i = 0; i < priceFluctuationArray.Length; i++)
            {
                //取得以i为子数组起点的 所有子数组 
                for (int j = i; j < priceFluctuationArray.Length; j++)
                {
                    //由i j 就确定了一个子数组
                    int totalTemp = 0;//临时 最大子数组的和 
                    for (int index = i; index < j + 1; index++)
                    {
                        totalTemp += priceFluctuationArray[index];
                    }
                    if (totalTemp > total)
                    {
                        total = totalTemp;
                        startIndex = i;
                        endIndex = j;
                    }
                }
            }
            Console.WriteLine("startindex : " + startIndex);
            Console.WriteLine("endIndex : " + endIndex);
            Console.WriteLine("购买日期是第" + startIndex + "天  出售是第" + (endIndex + 1)+"天");
            Console.ReadKey();
        }

2.就是本文所介绍的分治算法

解析思路:
把数组成为两部分,左边和右边两部分
那么就有三种情况
情况1:买入和卖出的日期均在左边
情况2:买入和卖出的日期均在右边
情况3:买入日期在左边,卖出时间在右边
最终比较三种情况的大小即可得出结果
介绍至此已经可以开始编程了

	class Program
	{
		//最大子数组的结构体
		struct SubArray
		{
			public int startIndex;
			public int endIndex;
			public int total;
		}
		static void Main(string[] args)
		{
			int[] priceArray = { 100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 79, 94, 90, 97 };
			int[] pf = new int[priceArray.Length - 1];//价格波动的数组
			for (int i = 1; i < priceArray.Length; i++)
			{
				pf[i - 1] = priceArray[i] - priceArray[i - 1];
				//Console.WriteLine(pf[i-1]);
			}
			int left = 0;
			int right = pf.Length - 1;
			var sub = GetMaxSub(left, right, pf);
			Console.WriteLine(sub.total);
			Console.ReadKey();
		}
		//这个方法是用来取得array 这个数组 从low到high之间的最大子数组
		private static SubArray GetMaxSub(int left, int right, int[] array)
		{
			if (left == right)
			{
				SubArray subArray;
				subArray.endIndex = right;
				subArray.startIndex = left;
				subArray.total = array[left];
				return subArray;
			}
			// 左边区间 [left,mid]  右边区间[mid+1,right]
			var mid = (left + right) / 2;
			//情况1:买入和卖出的日期均在左边
			var array1 = GetMaxSub(left, mid, array);
			//情况2:买入和卖出的日期均在右边
			var array2 = GetMaxSub(mid + 1, right, array);
			//情况3:买入日期在左边,卖出时间在右边
			int totalTemp1 = 0;
			int startIndex = mid;
			int endIndex = mid;
			int total1 = array[mid];
			for (int i = mid; i > 0; i--)
			{
				totalTemp1 += array[i];
				if (total1 < totalTemp1)
				{
					startIndex = i;
					total1 = totalTemp1;
				}
			}
			int totalTemp2 = 0;
			int total2 = array[mid + 1];
			for (int i = mid + 1; i > array.Length; i++)
			{
				totalTemp2 += array[i];
				if (total2 < totalTemp2)
				{
					endIndex = i;
					total2 = totalTemp2;
				}
			}
			SubArray array3;
			array3.endIndex = endIndex;
			array3.startIndex = startIndex;
			array3.total = total1 + total2;
			return GetMaxThree(array1, array2, array3);
		}
		private static SubArray GetMaxThree(SubArray sub1, SubArray sub2, SubArray sub3)
		{
			SubArray max;
			max.total = 0;
			//int temp=0;
			if (sub1.total > sub2.total && sub1.total > sub3.total)
			{
				return sub1;
			}
			else if (sub2.total > sub1.total && sub2.total > sub3.total)
			{
				return sub2;
			}
			else
			{
				return sub3;
			}

		}

	}

猜你喜欢

转载自blog.csdn.net/qq_34202873/article/details/87975494