分治算法-最大子数组问题
1.蛮力法求解
总体思路:
蛮力法是最简单的实现方法,只要列出数组所有可能的组合,然后找出其中和最大的组合即可;
蛮力法分三层循环实现:
1)第一层循环用于固定子数组的起始位置;
2)第二层循环用于确定子数组的结束位置;
3)第三层循环用于子数组和的计算,从子数组的头开始遍历到其尾,累加起来就是该子数组的和。
实现:
/// <summary> /// 暴力求解 /// </summary> /// <param name="priceArray"></param> /// <param name="priceFlutuationsArray"></param> public static void Violentsolution(int[] priceArray,int[] priceFlutuationsArray) { int total = priceFlutuationsArray[0];//默认数组得第一个元素 是最大子数组 int StartIndex = 0; int EndIndex = 0; for (int i = 0; i < priceFlutuationsArray.Length; i++) { //取得以i为子数组起点得 所有子数组 for (int j = i; j < priceFlutuationsArray.Length; j++) { //由i j就确定了一个子数组 int totalTemp = 0;//临时最大子数组得和 for (int k = i; k < j + 1; k++) { totalTemp += priceFlutuationsArray[k]; } if (totalTemp > total) { total = totalTemp; StartIndex = i; EndIndex = j; } } } Console.WriteLine("start:" + StartIndex); Console.WriteLine("End:" + EndIndex); Console.WriteLine("购买日期是第" + StartIndex + "天 出售日期是第" + (EndIndex + 1) + "天"); Console.WriteLine("total:" + total); }
2.分治法求解
总体思路:
分治法的精髓:
1)分--将问题分解为规模更小的子问题;
2)治--将这些规模更小的子问题逐个击破;
3)合--将已解决的子问题合并,最终得出“母”问题的解;
所以原数组的最大子数组求法:
1)分--将原数组拆分成两部分,每个部分再拆分成新的两部分......直到数组被分得只剩下一个元素;
2)治--每个小型的数组找最大子数组,只有一个元素的数组,解就是该元素;
3)合--将两个小型数组合并为一个数组,其中解有三种可能:
-
-
- 左边的返回值大,
- 右边的返回值大,
- 中间存在一个更大的子数组和;
-
返回值应选最大的;
实现:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 最大子数组问题 { 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]; } SubArray subArray = GetMaxSubArray(0, pf.Length - 1, pf); Console.WriteLine(subArray.startIndex); Console.WriteLine(subArray.endIndex); Console.WriteLine("我们在第" + subArray.startIndex + "天买入, 在第" + (subArray.endIndex + 1) + "天卖出"); Console.ReadKey(); } /// <summary> /// 这个方法用来取得array这个数组从low到high得最大子数组 /// </summary> /// <param name="low"></param> /// <param name="high"></param> /// <param name="array"></param> static SubArray GetMaxSubArray(int low,int high,int[] array) { if (low == high) { SubArray subarray; subarray.startIndex = low; subarray.endIndex = high; subarray.total = array[low]; return subarray; } int mid = (low + high)/2; //低区间[low,mid] 高区间[mid+1,high] SubArray subArray1= GetMaxSubArray(low, mid, array); SubArray subArray2=GetMaxSubArray(mid+1, high, array); SubArray subArray3 = GetMaxSub(low, mid, high, array); 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; } } static SubArray GetMaxSub(int low,int mid,int high,int[] array) { //从【low,mid】找到最大子数组[i,mid] int total1 = array[mid]; int startIndex = mid; int totalTemp = 0; for (int i = mid; i >= low; i--) { totalTemp += array[i]; if (totalTemp > total1) { total1 = totalTemp; startIndex = i; } } //从【mid+1,high】找到最大子数组[mid+1,j] int total2 = array[mid + 1]; int endIndex = mid + 1; totalTemp = 0; for (int j = mid + 1; j <= high; j++) { totalTemp += array[j]; if (totalTemp > total2) { total2 = totalTemp; endIndex = j; } } SubArray subArray3; subArray3.startIndex = startIndex; subArray3.endIndex = endIndex; subArray3.total = total1 + total2; return subArray3; } } }