![Python算法从菜鸟到达人](https://wfqqreader-1252317822.image.myqcloud.com/cover/713/41398713/b_41398713.jpg)
3.2 分治法
分治(Divide-and-Conquer)就是“分而治之”的意思,分治法的基本思想就是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相关联。通过递归方式来求解这些子问题,然后将各个子问题的解合并成原问题的解,如图3-1所示。它的一般的算法设计模式代码如下所示。
![](https://epubservercos.yuewen.com/F06DB7/21570844101311606/epubprivate/OEBPS/Images/32_02.jpg?sign=1738849079-N3U1IrLkIGZ3w2ob5mHDAA03bZ2c4xsx-0-b297112ae7b62119f695a94deb7a5610)
图3-1 分治法思想
![](https://epubservercos.yuewen.com/F06DB7/21570844101311606/epubprivate/OEBPS/Images/32_03.jpg?sign=1738849079-q1MebwEVLlhRul3oLQxM8Hwsj52kWrfR-0-6fbbeb063247db715ad4f6306e1f0817)
在用分治法设计算法时,最好使子问题的规模大致相同,即将一个问题分成大小相等的k个子问题(许多问题取k=2)。这种使子问题规模大致相等的做法出自一种平衡子问题的思想,通常比子问题规模不等的做法要好。
例3.3 分治法求数列中最大最小值。
问题描述:输入一个数组A[1,…, n],求出A中的最大值与最小值。
方法思想:使用分治法的思想,首先把数组分成两部分,再把这两部分中的每一部分再分成两部分,一直递归分解下去直到每一部分小于或等于两个数为止,然后比较这两个数大小,然后回弹比较直到递归的最外层,就可以找到数组中的最大最小值,代码如下所示。
![](https://epubservercos.yuewen.com/F06DB7/21570844101311606/epubprivate/OEBPS/Images/33_01.jpg?sign=1738849079-PNADXPwzMJhEVIAaPKtscYs3xe3D2dEZ-0-524159a238817a37b0c5ff0804ca2dd1)
伪代码已经给出了算法的逻辑,只需要根据Python语言的特性转换成Python的实现即可,实现代码如下:
![](https://epubservercos.yuewen.com/F06DB7/21570844101311606/epubprivate/OEBPS/Images/33_02.jpg?sign=1738849079-XurP7cUtYJJytEkNDXsGwkNZYlan3xyh-0-3ec68a91c583ff643ab9b1156ef92029)
![](https://epubservercos.yuewen.com/F06DB7/21570844101311606/epubprivate/OEBPS/Images/34_01.jpg?sign=1738849079-gpztuBDFg1ndxma3VnBPGsOEZRBl4bAi-0-d6a92619a23107a155dadd7359b99314)
程序运行结果为:
![](https://epubservercos.yuewen.com/F06DB7/21570844101311606/epubprivate/OEBPS/Images/34_02.jpg?sign=1738849079-UGkji5lvkK5e3rXvs8TCLUnpSq2kjtNg-0-b86b8a0913d398e8061bfe093fb45210)
现在来分析上述代码中算法的时间复杂度,用n表示待查找数组中元素的个数,用T(n)表示该问题的时间复杂度。根据算法中的递归关系可以得出:
![](https://epubservercos.yuewen.com/F06DB7/21570844101311606/epubprivate/OEBPS/Images/34_03.jpg?sign=1738849079-j8Xr2UPUd3Pgt2TD2yhpYHb5qIq1ZJ9A-0-f38cde006088018cd23ad06c724135d9)
根据上一章讲述的算法分析方法,可以得到。
总的来说,分治法所能解决的问题一般具有以下几个特征:
1)可行性。该问题的规模缩小到一定的程度时就可以容易地解决;因为问题的计算复杂性一般是随着问题规模的增加而增加,因此大部分问题满足这个特征。
2)可分解性。该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质,这条特征是应用分治法的前提,它也是大多数问题可以满足的,此特征反映了递归思想的应用。
3)可合并性。利用该问题分解出的子问题的解可以合并为该问题的解;能否利用分治法完全取决于问题是否具有这条特征,如果具备了前两条特征,而不具备第三条特征,则可以考虑贪心算法或动态规划。
4)独立性。该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。这条特征涉及分治法的效率,如果各子问题是不独立的,则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然也可用分治法,但用动态规划或贪心法会更好。
下面重点来分析分治法的复杂性,从一般设计模式看,用分治法设计的程序通常是一个递归算法。若一个分治法将规模为n的问题分成k个规模为n/m的子问题去解。假设规模为1的问题耗费1个单位时间,再设将原问题分解为k个子问题以及将k个子问题的解合并为原问题的解需用f(n)个单位时间。用T(n)表示该分治法求解规模为|P|=n的问题所需的计算时间,则有:
![](https://epubservercos.yuewen.com/F06DB7/21570844101311606/epubprivate/OEBPS/Images/34_05.jpg?sign=1738849079-lfAewM9Rawna5SoXskkWpL3jblQrlERo-0-79f5328db9c7eee32705cf27886ee641)
通过迭代法求得方程解为:
![](https://epubservercos.yuewen.com/F06DB7/21570844101311606/epubprivate/OEBPS/Images/34_06.jpg?sign=1738849079-ZY03cnZb69fuwb2TqHKG9YvUZ0Xy3b5k-0-7d8b7b13f233666c77f4442ef6dd0648)
其中,nlogmk为基本子问题所消耗的时间,则为合并部分所消耗的时间。设f(n)=Θ(nd), d≥0。依照主定理可得:
![](https://epubservercos.yuewen.com/F06DB7/21570844101311606/epubprivate/OEBPS/Images/35_01.jpg?sign=1738849079-JHOKSCY4T245csZgHBBSz7r1bNHCvWCV-0-4be9c3001afcb2a13e4e16c2b7ac7675)