一、最大子数组问题
1、实际问题背景
我们进行股票交易的时候,可以估计一短时间的股票估值,我们总是喜欢最低价买入,最高价卖出,寻求利益最大化。在现实中我们很有可能遇到最高价在前,最低价在后的情况,这就需要我们不能简单的找最大值和最小值,而是需要对于一段时间的股票价值求最大交易利益。
2、最大和子数组问题
我们把实际问题可以抽象出来:
我们寻找一段时间的最大利润,那就可以抽象出一个数组。然后我们定义第i ii个数据代表第i天和第i − 1 i-1i−1天的价格差,数组的第一个数据是第2天的价格与第1天价格的差值。那么问题就转化为寻找数组的最大和的非空连续子数组。我们称这个问题为最大和子数组问题。
3、暴力求解
我们很容易设计出一种暴力求解办法,可以直接计算出每一种组合的和,然后得到和最大的组合以及最大和。时间复杂度为Ω(n^2 )。
二、分治思想
分治法:1、把一个问题分成(同类的)几个子问题。2、递归地解决(征服)每个子问题。3、将子问题的解决方案组合成整体解决方案。
分治法问题的关键在于:如何去分以及分成什么样的子问题是可以解决的。
1、如何去分:
对于数组arr的切片[low, high],可以选择其中间结点mid,则可以将数组分为[low, mid]、[mid+1, high]、则可以认为答案在一下三种情况中:
1.中间结点左边的最大子数组
2.中间结点右边的最大子数组
3.包含中间结点的最大子数组
2、什么样的子问题可以解决:
1.对于情况1,2,则可以继续往下细分。
2.对于情况3,由于本身就是细分的结果,所以需要进行直接求解
3.细分下去最终会进入low = high的情况,也就是子数组只有一个元素
3、对于子数组只有两个元素(low与high)的情况
1.在该情况下,我们已知中间结点的左右边最大子数组就是该元素.
2.对于情况3:将两个元素相加后得到sum,将sum与其他两个值比较,最大的那个对应的子数组作为该字数的最大子数组,并记录。
三、伪算法求解
1 left_sum = -∞ //左数组的最大子数组的值
2 sum=0 //数组的值
3 for i = mid downto low //从中间结点开始向低结点加上去。
4 sum = sum+A[i]
5 if sum>left_sum //这里是找到左半部分最大和,以及最大值所对应的数组
6 left_sum = sum
7 max_left = i //left_sum与max_left分别是左半部最大和以及最大和对应的数组的左边界
8 right_sum = -∞
9 sum=0
10 for j =mid +1 to high
11 sum = sum+A[j]
12 if sum>right_sum //这里是找到右半部分最大和,以及最大值所对应的数组 的最右边的数的索引,分别用right_sum和max_right记录
13 right_sum = sum
14 max_right = j
15 return (max_left,max_right,left_sum+right_sum) //返回左部最大值,右部最大值以及二者和中最大的值
四、关于分治思想的一些问题
1、分治思想的时间复杂度:T(n)
当n=1时,T(n)=θ(1)
当n>1时,根据2.2的情况分法,情况1,2可以继续细分下去即时间复杂度为T(n/2),情况3需要遍历子数组的每一个元素所以时间复杂度为θ(n):
T(n)=2T(n/2)+θ(n)
综上所述:T(n)=2T(n/2)+θ(n) / T(n) = θ(n lgn)
2、分治思想的优点
分治策略相比于传统的多重循环解决策略往往有执行时间少的优势,这个优势的来源于分治策略所用的思想:空间换时间与树的数据结构