给出一个数组
int[] priceArray = { 100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 79, 94, 90, 97 };
求其中的最大子数组
暴力求解
思路:通过两层for循环遍历该数组中的每一个子数组,然后统计每一个子数组的和,每求出一次子数组的和便进行一次判断,来保存下最大子数组和对应的下标。
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], startIndex = 0, endIndex = 0;
for(int i = 0; i < priceFluctuationArray.Length; i++)
{
for(int j = i; j < priceFluctuationArray.Length; j++)
{
int temp = 0;
for(int index = i; index <= j; index++)
{
temp += priceFluctuationArray[index];
}
if (temp > total)
{
total = temp;
startIndex = i;
endIndex = j + 1;
}
}
}
Console.WriteLine($"start:{startIndex},end:{endIndex},total:{total}");
}
}
上列代码中采用了三层for循环,前面两层是遍历全部子数组,最后一层则是将该子数组求和,性能耗费很大,但是也算是一种求解方法,建议走投无路的时候再采用。
分治法
分治法则是采用二分法和递归来实现。
首先取得中间值mid。
所有的情况分为以下三大类
- 位于低区间
- 位于高区间
- 跨区间
1与2的情况都可以归为求区间内的最大子数组问题,这么一想是不是就和最开始要求的问题一样了?只不过是将一个大区间划分为小区间进行操作,所以1和2的情况便是可以通过递归操作来进行完成。
每一个递归都需要设定终止条件,在无法继续划分更小的区间的时候,便是结束递归的时候,也就是 low == high的时候便结束递归。
最后是情况3,我们需要对低区间求出最大的子数组,对高区间求出最大子数组,两者子数组之和便是我们所需要的结果。
讨论完以上三种情况,我们需要的是对所有的情况进行一个结果的对比,取出最大的值。
struct MaxSubArr
{
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[] priceFluctuationArray = new int[priceArray.Length - 1];
for (int i = 1; i < priceArray.Length; i++)
{
priceFluctuationArray[i - 1] = priceArray[i] - priceArray[i - 1];
}
MaxSubArr arr = GetMaxSubArr(0, priceFluctuationArray.Length - 1, priceFluctuationArray);
Console.WriteLine($"开始{arr.startIndex},结束{arr.endIndex + 1},总和{arr.total}");
}
static MaxSubArr GetMaxSubArr(int low,int high,int[] arr)
{
if(low == high)
{
MaxSubArr Arr;
Arr.startIndex = low;
Arr.endIndex = high;
Arr.total = arr[low];
return Arr;
}
int mid = (low + high) / 2;
//低区间
MaxSubArr Arr1 = GetMaxSubArr(low, mid, arr);
//高区间
MaxSubArr Arr2 = GetMaxSubArr(mid + 1, high, arr);
//低高区间
int startIndex = mid, endIndex = mid + 1, total1 = 0, total2 = 0, tempTotal = 0;
for(int i = mid; i >= low; i--)
{
tempTotal += arr[i];
if(tempTotal > total1)
{
total1 = tempTotal;
startIndex = i;
}
}
tempTotal = 0;
for(int i = mid+1;i <= high; i++)
{
tempTotal += arr[i];
if (tempTotal > total2)
{
total2 = tempTotal;
endIndex = i;
}
}
MaxSubArr Arr3;
Arr3.startIndex = startIndex;
Arr3.endIndex = endIndex;
Arr3.total = total1 + total2;
if (Arr1.total > Arr2.total && Arr1.total > Arr3.total)
{
return Arr1;
}else if(Arr2.total > Arr1.total && Arr2.total > Arr3.total)
{
return Arr2;
}
else
{
return Arr3;
}
}