分治算法:把一个规模较大的复杂问题拆分成一些规模较小的问题,规模较小的问题继续拆分,直到这个问题变得不复杂,能解决为止。
分治算法解决的一些问题:二分搜索
大整数乘法
合并排序
快速排序
线性时间排序
最大子数组
详细分析最大子数组:最大子数组有两种解决方法,1:暴力求解。2:用分治算法.
暴力求解:直接用循环把数组的所有子数组组合出来,算出所有子数组的和,比较大小,得到最大的子数组和。
分治算法解:最大子数组问题用分治算法分解,设最大子数组的开始下标为i,结束下标为j,把数组平分成两部分[0,mid]和[mid+1,length],i 和j可能在前半部分,也有可能在后半部分,也有可能i在前半部分,j在后半部分,分成这三个部分考虑,如果在前半部分求他的最大子数组,还可以用这个思想把前半部分的数组拆成两个,在讨论,数组一直可以继续拆,直到数组只剩两个数,两个数是分类讨论的最小情况了,这个时候问题也变得十分简单了,就可以求出最大子数组了。
最大子数组问题一般是由一些具体问题归成的,比如计算售卖商品,那上面的为例,你求价格的最大子数组是没有任何意义的,算出他们的变化的最大子数组是有具体意义的,可以得到他们在哪一段时间出售挣得最多。像股票等,都是这么分析的,得到他们变化值的最大子数组才有意义。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Maxarray { class Program { /// <summary> /// 用一个结构体存储最大字数组的值,和他在数组中的开始下标和结束下标 /// </summary> struct MaxArray { public int value; public int LowIndex; public int HighIndex; } static void Main(string[] args) { List<int> arraylist = new List<int> { 100,113,110,85,105,102,86,63,81,101,94,106,101,79,94,90,97};//实际问题的数组值 int[] pf = new int[arraylist.Count-1]; for (int i = 0; i < arraylist.Count-1; i++)//算出每一天较前一天的的变化值,以便直关的显示每一天的盈亏情况 { pf[i] = arraylist[i + 1] - arraylist[i]; } MaxArray max= maxSonAaary(0, pf.Length-1, pf); Console.WriteLine(max.value);//得到最大子数组的总和 Console.WriteLine("最大子数组是从下表为{0}到下标为{1}",max.LowIndex,max.HighIndex); Console.ReadKey(); } /// <summary> /// 采用分治算法将数组拆分成许多小数组,不断拆分,拆成最小的数组,进行计算,具体实现使用回调函数。 /// </summary> /// <param name="low"></param> /// <param name="high"></param> /// <param name="array"></param> /// <returns></returns> static MaxArray maxSonAaary(int low,int high,int[] array) { if(low==high)//拆成一个数组只有一个值时,停止分解 { MaxArray arrayMax; arrayMax.value = array[low]; arrayMax.LowIndex = low; arrayMax.HighIndex = high; return arrayMax; } int mid = (low + high) / 2; MaxArray arrayMax1= maxSonAaary(low, mid, array); MaxArray arrayMax2= maxSonAaary(mid + 1, high, array); MaxArray arrayMax3=new MaxArray(); arrayMax3.LowIndex = mid; arrayMax3.HighIndex = mid + 1; int ArraySum = 0; int total = array[mid]; for (int i = mid; i >=low; i--) { ArraySum += array[i]; if(ArraySum>total) { total=ArraySum; arrayMax3.LowIndex = i; } } int total1 = array[mid + 1]; int ArraySum1 = 0; for (int i = mid+1; i <= high; i++) { ArraySum1 += array[i]; if(ArraySum1>total1) { total1 = ArraySum1; arrayMax3.HighIndex = i; } } arrayMax3.value = total+total1; if(arrayMax1.value>=arrayMax2.value&&arrayMax1.value>=arrayMax3.value) { return arrayMax1; } else if(arrayMax2.value>=arrayMax1.value&&arrayMax2.value>=arrayMax3.value) { return arrayMax2; } else { return arrayMax3; } } } }
暴力求解最大子数组
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MaxArray { class Program { static void Main(string[] args) { int[] array = new int[] { 100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 79, 94, 90, 97 }; int[] SonArray = new int[array.Length - 1]; for (int i = 0; i < SonArray.Length; i++)//以前一天为标准,算出那些天是较前一天是增加还是减少 { SonArray[i] = array[i + 1] - array[i]; } int MinIndex; int MaxIndex; int MaxValue= MaxSonArray(out MinIndex,out MaxIndex,SonArray); Console.WriteLine("最大子数组值{0},成员从{1}到{2}",MaxValue,MinIndex+1,MaxIndex+1); Console.ReadKey(); } /// <summary> /// 暴力求解出数组的最大子数组 /// </summary> /// <param name="MinIndex"></param> /// <param name="MaxIndex"></param> /// <param name="array"></param> /// <returns></returns> public static int MaxSonArray(out int MinIndex,out int MaxIndex,int[] array) { MinIndex = 0; MaxIndex = 0; int MaxValue = 0; for (int i = 0; i < array.Length; i++) { int tempValue = 0; for (int j=i;j<array.Length;j++) { tempValue += array[j]; if(MaxValue<tempValue) { MaxValue = tempValue; MinIndex = i; MaxIndex = j; } } } return MaxValue; } } }