求一个整数序列中的最大和最小元素
算法思想:
本题为无序序列查找最大/最小元素位置问题。
要求采用分治法求解,则与称假币问题的思路类似。
思路:(以查找最大元素为例)
对arr[low…high]求最大值max0
并分为arr[low…mid0]、arr[mid0+1…high]左右两段
再对分别对arr[low…mid0]和arr[mid0+1…high]求最大值max1L,max1R
每次将一段大区域划分为小区域
并在两个小区域中找到最大值与原来区域最大值相同的区域
,接着划分,递归上面过程,
由于partition过程不断缩小搜索范围,总能找到最大值所在位置。
检查最大值在左半段还是右半段中,若在左半段中
继续对左半段进行二分,分成两个更小的半段,求max2L,和max2R
检查最大值在小左半段还是小右半段,若在小左半段中
则继续对小左半段进行二分。。。
重复以上步骤,直至含有最大值的一段无法再分(只有一个元素),则该元素就是最大值,则该元素所在位置便是所求位置。
使用分治法实现归并排序
算法思想:
归并排序是分治法的经典案例,基本思想是将整体问题转换为局部问题,将局部问题的解最终合成整体解。
归并排序将序列分割为各个单元素:
例如:
[3 1 2 6 5 7 9]
划分为:
[3] [1] [2] [6] [5] [7] [9]
选取2个为一组对元素进行合并、排序(在此选2为合并的个数)
[3 1] [2 6] [5 7] [9]
重复以上过程直至合成为一个序列
再次合并,排序(下面将合并排序整合为一步)
[1 2 3 6] [5 7 9]
再次进行合并,排序
[1 2 3 5 6 7 9]
当重新合并为一个序列时,序列已经变成有序序列。
从整体—>局部—>整体的这种解题方法就是分治法
归并排序使用自下而上的分治法,也可以使用自上而下的快速排序对序列进行排序。
使用分治法实现快速排序
简述:
常见的快排有3种类型
1.二分快排:
以序列的最后一个数num做划分值,将≤num的元素放左侧,>num的元素放在右侧,
再将>num的第一个元素与划分值位置交换,使得左侧区域扩充一个元素,
且该元素位置被固定下来。
取左侧区域的最后一个元素(num之前的元素)与右侧区域的最后一个元素
分别作为划分值对两个区域接着划分,重复这样的递归过程。
对于划分区域来说每次划分都会固定一个元素,
左右分区做递归, partition下去,总会让序列彻底有序。
2.三分快排:
与二分快排类似,选最后一个值num作为划分值将序列分为,<num,=num,>num三个区域,
分完后将>num区域的第一个元素与num交换,
导致中间全为num,中间的值就固定下来,
每次递归都会固定下来至少一个数
再对<num,>num区域重复partition过程,总会能使得序列有序。
三分快排比二分快排稍快,它一次可以排多个元素。
但无论上面两个的哪一种排序,时间复杂度都是O(n^2)
,因为划分值的位置是人为选取的,
因此总能举出最差的例子(1,2,3,4,5,6,7,8,9,10)
该序列每次partition只解决一个数。时间复杂度O(n^2)
3.随机划分值快排:
利用随机数取划分值,使得时间复杂度接近O(n*logN)
(该时间复杂度由概率论中,由于浮点数分布被认为是连续分布,单个点对整体影响可忽略,由期望和的累加公式求得,长期期望。算出每种情况的出现的概率以及对应的时间复杂度做积,相加,最终结果就是nlogN)
分治法求解最大子段和
分治法求最大子段和:
将整个大数列分为左右两个部分:则最大连续子数列应该在以下3种情况中
- 完全包含在左半部分的数列中
- 完全包含在右半部分的数列中
- 横跨分割点,左右各占一部分
第1,2种情况可利用递归,不断对整个数列进行partition得到结果。
而第3种情况依赖于第1,2种情况,因此递归会从高—>低 在算出最底层第一二种情况后 再从低—>高 回推给上层,算出第三种情况的结果,三种情况取最大值,就是本题的解
使用分治法对递增有序序列a求众数
分治法求众数类似于荷兰国旗问题,而此序列已经有序
因此,只需要找到中间值,
与中间值相等的数为一个区域,<中间值的为一个区域,>中间值的为一个区域,
将序列划分为3部分<mid,=mid,>mid,
记录=mid区域中元素值个数max,
并在递归过程中不断更新max
继续对<mid,>mid区域递归上述过程,直到区域划分为1或0。
最终max的最大值就是整个序列的众数。