分治算法
- 分治算法介绍
- 二分搜索
- 大整数乘法
- 棋盘覆盖
- 合并排序
- 快速排序
- 线性时间选择
- …
分治算法介绍:简单点理解就是分开处理,如果一个问题可以容易的解决,则直接解决,否则将其分解为规模较小的子问题去解决,子问题与原问题形式相同,递归子问题,然后将子问题的解合并。
如问题一如果卖出黄金,求黄金最大收益:
天 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
黄金价格 | 50 | 65 | 75 | 65 | 66 | 68 | 68 | 56 | 78 | 80 | 75 | 72 | 70 | 70 | 71 |
波动 | 0 | 15 | 10 | -10 | 1 | 2 | 0 | -12 | 22 | 2 | -5 | -3 | -2 | 0 | 1 |
解决方法:(最大子数组)
- 暴力求解(吞吐量大)
- 分治法
一、暴力求解
static void Main (string[] args) {
// 黄金价格
int[] pPriceArray = { 50, 65, 75, 65, 66, 68, 68, 56, 78, 80, 75, 72, 70, 70, 71 };
// 波动的价格
int[] pPriceWaveArray = new int[pPriceArray.Length - 1];
for (int i = 1; i < pPriceArray.Length; i++) {
pPriceWaveArray[i - 1] = pPriceArray[i] - pPriceArray[i - 1];
}
// 默认最大子数组是第一个元素
int pMaxTatal = pPriceWaveArray[0];
int pStartIndex = 0;
int pEndIndex = 0;
for (int i = 0; i < pPriceWaveArray.Length; i++) {
// 取得所有子数组
for (int j = i; j < pPriceWaveArray.Length; j++) {
int pTempMaxTotal = 0;
for (int k = 0; k < j + 1; k++) {
pTempMaxTotal += pPriceWaveArray[k];
if (pTempMaxTotal > pMaxTatal) {
pMaxTatal = pTempMaxTotal;
pStartIndex = i;
pEndIndex = j;
}
}
}
}
Console.WriteLine("Start Index: " + pStartIndex);
Console.WriteLine("End Index: " + (pEndIndex + 1));
Console.WriteLine("buy day: " + pStartIndex + "Sell Day: " + (pEndIndex + 1));
Console.ReadKey();
}
二、分治法
// 子数组
struct MaxArray {
public int pStartIndex;
public int pEndIndex;
public int pSubTotal;
}
static void Main (string[] args) {
// 黄金价格
int[] pPriceArray = { 50, 65, 75, 65, 66, 68, 68, 56, 78, 80, 75, 72, 70, 70, 71 };
// 波动的价格
int[] pPriceWaveArray = new int[pPriceArray.Length - 1];
for (int i = 1; i < pPriceArray.Length; i++) {
pPriceWaveArray[i - 1] = pPriceArray[i] - pPriceArray[i - 1];
}
MaxArray pMaxArray = GetMaxArray(0, pPriceWaveArray.Length - 1, pPriceWaveArray);
Console.WriteLine("Buy Day: " + pMaxArray.pStartIndex);
Console.WriteLine("Sell Day: " + (pMaxArray.pEndIndex + 1));
Console.ReadKey();
}
// 取数组中从low到high中的子数组
static MaxArray GetMaxArray (int low, int high, int[] array) {
if (low == high) {
MaxArray pMaxArray;
pMaxArray.pStartIndex = low;
pMaxArray.pEndIndex = high;
pMaxArray.pSubTotal = array[low];
return pMaxArray;
}
// low区间[low,mid] 高区间[mid+1,high]
int pMidIndex = (low + high) / 2;
MaxArray pMaxArray1 = GetMaxArray(low, pMidIndex, array);
MaxArray pMaxArray2 = GetMaxArray(pMidIndex + 1, high, array);
// 从[low,mid]找最大子数组[i , mid]
int pSubTotalLow = array[pMidIndex];
int pStartIndex = pMidIndex;
int pSubTempTotal = 0;
for (int i = pMidIndex; i >= low; i--) {
pSubTempTotal += array[i];
if (pSubTempTotal > pSubTotalLow) {
pSubTotalLow = pSubTempTotal;
pStartIndex = i;
}
}
// 从 [mid+1,high]找到最大子数组[mid+1,j]
int pSubTotalHigh = array[pMidIndex + 1];
int pEndIndex = pMidIndex + 1;
pSubTempTotal = 0;
for (int j = pMidIndex + 1; j <= high; j++) {
pSubTempTotal += array[j];
if (pSubTempTotal > pSubTotalHigh) {
pSubTotalHigh = pSubTempTotal;
pEndIndex = j;
}
}
MaxArray pMaxArray3;
pMaxArray3.pStartIndex = pStartIndex;
pMaxArray3.pEndIndex = pEndIndex;
pMaxArray3.pSubTotal = pSubTotalLow + pSubTotalHigh;
if (pMaxArray1.pSubTotal >= pMaxArray2.pSubTotal && pMaxArray1.pSubTotal >= pMaxArray3.pSubTotal) {
return pMaxArray1;
} else if (pMaxArray2.pSubTotal >= pMaxArray1.pSubTotal && pMaxArray2.pSubTotal >= pMaxArray3.pSubTotal) {
return pMaxArray1;
} else {
return pMaxArray3;
}
}
大概图解