首先咱們要考慮使用遞歸的2個條件,原問題是否能夠分解爲形式相同但規模更小的問題,還有就是若是存在這樣的分解,那麼這種分解是否存在一種簡單情境?ios
先來看第一點,是否存在一種符合條件的分解。容易發現,若是一個字符串是迴文,那麼在它的內部必定存在着更小的迴文。 好比level裏面的eve也是迴文。 並且,咱們注意到,一個迴文的第一個字符和最後一個字符必定是相同的。因此咱們很天然的有這樣的方法:先判斷給定字符串的首尾字符是否相等,若相等,則判斷去掉首尾字符後的字符串是否爲迴文,若不相等,則該字符串不是迴文。 注意,咱們已經成功地把問題的規模縮小了,去掉首尾字符的字符串固然比原字符串小。web
接着再來看第二點, 這種分解是否存在一種簡單情境呢?簡單情境在使用遞歸的時候是必須的,不然你的遞歸程序可能會進入無止境的調用。對於迴文問題,咱們容易發現,一個只有一個字符的字符串必定是迴文,因此,只有一個字符是一個簡單情境,但它不是惟一的簡單情境,由於空字符串也是迴文。這樣,咱們就獲得了迴文問題的兩個簡單情境:字符數爲1和字符數爲0。算法
好了,兩個條件都知足了,基於以上分析,咱們能夠很容易的編寫出解決迴文問題的遞歸實現方式,數組
剛開始寫的代碼是這樣:函數
int isPalindrome(char *s,int n) { if(n==0 || n==1) return 1; else { return ((s[0]==s[n-1]))?isPalindrome(s+1,n-1):0; } }
這樣的代碼對嗎?輸入"aba",會發現輸出的是0,不是1.spa
說明代碼錯誤爲何?首先func(aba,3)->func(ba,2)code
s[0]=b, s[1]=a;//明顯不相等,返回0.blog
從上面的函數調用過程咱們能夠看出爲何錯了?緣由在於排序
每次比較後,n應該是減2而不該該是減1.(去掉了2個字符)遞歸
從上面錯誤的代碼中,咱們稍微改下寫成以下的代碼:
int isPalindrome(char *s,int n) { if(n==0 || n==1) return 1; else { return ((s[0]==s[n-1]))?isPalindrome(s+1,n-2):0; } }
程序正確。
還能夠這麼寫:
int isPalindrome2(char *s,int b,int e) { if(b==e || b>e) { return 1; } else { return s[b]==s[e]?isPalindrome2(s,b+1,e-1):0; } }
注意base case:爲奇數時b==e,偶數時b>e.
這種方式更好理解。
還有一個典型的例子是對已排序數組的二分查找算法。
如今在有一個已經排序好的數組,要在這個數組中查找一個元素,以肯定它是否在這個數組中,很通常的想法是順序檢查每一個元素,看它是否與待查找元素相同。這個方法很容易想到,但它的效率不能讓人滿意,它的複雜度是O(n)的。如今咱們來看看遞歸在這裏能不能更有效。
仍是考慮上面的兩個條件: 第一:這個問題是否能夠分解爲形式相同但規模更小的問題?第二:若是存在這樣一種分解,那麼這種分解是否存在一種簡單情境?
考慮條件一:咱們能夠這樣想,若是想把問題的規模縮小,咱們應該作什麼?能夠的作法是:咱們先肯定數組中的某些元素與待查元素不一樣,而後再在剩下的元素中查找,這樣就縮小了問題的規模。那麼如何肯定數組中的某些元素與待查元素不一樣呢? 考慮到咱們的數組是已經排序的,咱們能夠經過比較數組的中值元素和待查元素來肯定待查元素是在數組的前半段仍是後半段。這樣咱們就獲得了一種把問題規模縮小的方法。
接着考慮條件二:簡單情境是什麼呢? 容易發現,若是中值元素和待查元素相等,就能夠肯定待查元素是否在數組中了,這是一種簡單情境,那麼它是否是惟一的簡單情境呢? 考慮元素始終不與中值元素相等,那麼咱們最終可能獲得了一個沒法再分的小規模的數組,它只有一個元素,那麼咱們就能夠經過比較這個元素和待查元素來肯定最後的結果。這也是一種簡單情境。
好了,基於以上的分析,咱們發現這個問題能夠用遞歸來解決,二分法的代碼以下:
int binarySearch2(int * a, int n, int key) { int mid; if(n == 1){ return (a[0] == key); }else{ mid = n/2; if(a[mid-1] == key) return 1; else if(a[mid-1] > key) return binarySearch2(a, mid, key); else return binarySearch2(a[mid], n - mid, key); } }
這個算法的複雜度是O(logn)的,顯然要優於先前提到的樸素的順序查找法。
好了,今天就說到這裏,光看無論用,不如留個練習題您回去作作:
寫一個函數dig sum(int n),輸入一個非負整數,返回組成它的數字之和。如:digsum(2007) = 2+0+0+7 = 9。
參考:
http://www.pureweber.com/article/recursive-power-2/
個人代碼:
#include<iostream> using namespace std; int binarySearch(int a[],int b,int e,int key) { if(b>e) { return -1; } int mid=(b+e)/2; if(a[mid]==key) return mid; else if(a[mid]<key) return binarySearch(a,mid+1,e,key); else return binarySearch(a,b,mid-1,key); } int main() { int a[]={1,3,4,5}; cout<<binarySearch(a,0,(sizeof(a)/sizeof(a[0]))-1,0); }