分治算法
1. 前言
本節(jié)內(nèi)容是分治算法系列之一:分治算法的介紹,主要介紹了分治算法的定義及基本思想和實(shí)現(xiàn)策略,然后我們介紹了一下分治算法的實(shí)現(xiàn)步驟,最后說明了一下哪些問題適合應(yīng)用分治算法求解分析。
2. 什么是分治?
在計(jì)算機(jī)科學(xué)與技術(shù)領(lǐng)域中,分治法(Divide and Conquer) 是一種常見的算法思想。
分治法的理解其實(shí)很簡(jiǎn)單,直接按照字面的意思理解就可以:“分而治之”。分(divide)是將一個(gè)大的問題分解成一些小的問題分別求解,治 (conquer)則是將分解的問題答案合并在一起,整個(gè)過程則是分而治之。這個(gè)算法技巧是很多算法的基礎(chǔ),我們之前學(xué)過的快速排序,其中就有分治思想的應(yīng)用。
簡(jiǎn)單來說,分治法就是將一個(gè)復(fù)雜的大問題分解成兩個(gè)或者更多相同或者相似的子問題,再把子問題繼續(xù)拆分成更小的子問題,直到子問題可以直接求解,然后原問題的解就是子問題的解的合并。
3. 分治法的基本思想及實(shí)現(xiàn)策略
主要思想:分治法將一個(gè)規(guī)模較大的問題,拆分成一些規(guī)模較小的相同問題,小問題各個(gè)求解,再合并成大問題的解。這個(gè)是分值算法的主要思想。
實(shí)現(xiàn)策略:分治算法對(duì)于一個(gè)規(guī)模較大 的問題(假設(shè)其規(guī)模為 n ),如果當(dāng)規(guī)模 n 的問題很容易解決則直接解決;否則就將這個(gè)規(guī)模為 n 的大問題拆分為幾個(gè)規(guī)模為 k (規(guī)模 k 小于規(guī)模 n ) 的子問題,這些子問題與原問題的形式相同,則可以遞歸地求解這些子問題,然后將各個(gè)子問題的解合并得到原先的大問題的解。
分治法是否可行主要就在于這個(gè)大問題是否可以拆分為相同形式的小問題,然后這些小問題可解并將小問題的解合并成為原問題的解。因此,分治法所能夠解決的問題一般都會(huì)具有如下幾個(gè)特征:
- 待求解問題可以拆分成相同形式的規(guī)模較小的問題;
- 待求解問題在規(guī)??s小到一定程度之后就可以很容易求解;
- 利用待求解問題拆分出的子問題的解可以合并為待求解問題的解;
- 待求解問題拆分出來的子問題是相互獨(dú)立的,子問題之間不會(huì)包含相同的子問題。
4. 分治法的基本步驟
在明確分治法的定義及其主要思想和實(shí)現(xiàn)策略之后,我們需要掌握實(shí)現(xiàn)分治法的主要步驟:
-
步驟 1:
將待求解問題拆分成若干個(gè)規(guī)模較小、相互獨(dú)立的子問題,子問題的形式與待求解問題相同;
-
步驟 2:
若干個(gè)子問題如果很容易求解則直接求解,如果不容易求解則遞歸的解各個(gè)子問題;
-
步驟 3:
將各個(gè)子問題分別求解的結(jié)果合并成待求解問題的解。
基于以上的三個(gè)步驟,分治算法一般可以總結(jié)成下面的偽代碼:
divideAndConquer(big_problem){
if (canSolve(big_problem)){ //問題可以直接求解則直接求解返回
solve(big_problem); //求解
return;
}else {
small_problem_A = divide(big_problem); //不能直接求解的問題拆分
small_problem_B = divide(big_problem); //不能直接求解的問題拆分
divideAndConquer(small_problem_A); //遞歸求解子問題
divideAndConquer(small_problem_B); //遞歸求解子問題
return merge(); //合并子問題的解
}
}
5. 分治法的應(yīng)用場(chǎng)景
在日常的生活學(xué)習(xí)中,分治算法一般可以用來解決很多實(shí)際問題。下面,我們來看兩個(gè)分治算法求解問題的實(shí)例。
實(shí)例 1: 二分搜索
二分搜索是一種很常見的搜索策略,他的核心思想也是利用到分治算法。二分搜索是在一個(gè)有序的數(shù)組中,通過均勻二分,每次折半查找,就是應(yīng)用到分治法中將大問題縮減到小問題,這個(gè)小問題的最后結(jié)果就是剛好找到需要查找搜索的元素,這樣小問題得出解,這個(gè)解也是最開始的待搜索的元素。
實(shí)例 2: 全排列問題
現(xiàn)實(shí)生活中,我們經(jīng)常會(huì)遇見這樣的場(chǎng)景,比如有 3 個(gè)小朋友排成一列,問你一共有多少種可以排列的情況,這個(gè)問題類似于數(shù)學(xué)中的全排列問題,這個(gè)時(shí)候利用分治算法也可以很好地進(jìn)行求解。
先依次從三個(gè)小朋友中選擇一位排在隊(duì)列最前面,剩下的兩個(gè)小朋友可以進(jìn)行全排列,也可以繼續(xù)拆分,二者選擇其一進(jìn)行即可,這個(gè)時(shí)候其實(shí)很清楚,他們只有兩種排列情況了,然后跟前面的小朋友排列組合在一起。
比如我們用 A,B,C 代表三個(gè)小朋友,他們的排列情況演示如下:
//初始需要排列的元素
[A,B,C]
//依次從三個(gè)小朋友中選擇一位排在隊(duì)列最前面,剩下的兩個(gè)小朋友全排列
A[B,C]; B[A,C]; C[A,B]
//剩下的兩個(gè)小朋友排列情況只有兩種,與之前的合并在一起
ABC,ACB,BAC,BCA,CAB,CBA
在現(xiàn)實(shí)工作和學(xué)習(xí)中會(huì)經(jīng)常遇見,這是一種解決問題的思路與方法,將待求解的大問題拆分成小問題,然后解決小問題,再將小問題的解合并得出整個(gè)問題的解。
6. 小結(jié)
本節(jié)主要介紹了分治算法的定義及基本思想,在學(xué)完本節(jié)課程之后,需要明白分治算法的基礎(chǔ)思想和實(shí)現(xiàn)邏輯是什么樣的,如何自己去設(shè)計(jì)一個(gè)分治算法,什么樣的問題適合用分治算法求解,以及在我們?nèi)粘V谐R姷姆种嗡惴ㄇ蠼獾膯栴}。