如何才能輕而易舉的寫出遞迴函式

2021-10-23 17:28:20 字數 3245 閱讀 4770

首先,我想說下我的學習方式,每個人的學習方式都是不同的,有的人悟性比較高,所以學東西比較快,但也有一部分人,學東西比較慢,哈哈,我就是那學東西比較慢的那一部分人。但我也不氣餒,認真踏實的學就可以了,千萬不能浮躁。

所以在我學習演算法的過程中,首先要搞懂這個技術是來解決什麼問題的,這是很重要的一步,其次如何使用,最後它的原理是什麼。走好這三步我覺得這個技術你也就學會了。

首先第一步,遞迴這個演算法是用來解決什麼問題的或者主要用於什麼方向的。在我目前的理解,遞迴主要是將乙個大問題分解成小問題,最後各個小問題的解再進行合併。這就是遞迴的主要作用。

注意兩個技巧來編寫遞迴函式:

例項:輸入: 10

輸出: 36

解釋: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。

首先如何思考題目:說至少拆分成兩個數,那麼拆分出來的兩個數是否又可以進行拆分?

就好比10拆分成10=4+6,那麼6是否可以拆分成4+2?是不是有一點激動,是不是很像遞迴,將乙個大問題拆分成乙個個小問題。

那麼知道了方法,那思路是怎麼的呢?我們可以將乙個數從1進行拆分,一直到n-1。打個比方吧,比如10,我們乙個個拆分成【1,9】,【2,8】,【3,7】…【9,1】,那麼在拆分的過程中,比如拆分成【1,9】,9是否又可以進行拆分?是重複的乙個過程,但就是這個過程我們定義成了遞迴函式,所以遞迴函式的功能就是給你乙個數返回它的乘積最大化結果。

那我們現在就來定義遞迴函式的功能:

//遞迴函式的功能定義非常重要: 

public

inthelp

(int num)

int res=0;

for(

int i=

1;i)return res;

}

上面那道題就完成了,但是寫成那樣,時間複雜度比較高,應該不可能通過所有測試用例,所以我們要利用hashmap來記錄乙個正整數的最大化乘積的值,避免重複計算。這種方式就是備忘錄方法。

hashmap

map=

newhashmap

<

>()

;public

inthelp

(int num)

//主要新增了下面三行**,你們想要,我求出了10的最大化,

//是不是要進行儲存起來,因為10的最大化是乙個固定值,不是變化的,所以當再用到10這個正整數的時候

//就無須再進行計算了,直接返回他的結果就可以了

if(map.

containskey

(num)

)int res=0;

for(

int i=

1;i)//將num這個正整數的最大化乘積res進行儲存

map.

put(num,res)

;return res;

}

到目前為止,這道題才算是解決了。

計算在不觸動警報的情況下,小偷一晚能夠盜取的最高金額。

這一題如何思考呢?在我認為遞迴最要緊的就是定義函式功能,這一題的遞迴函式功能是什麼呢?那就是給你乙個二叉樹中的任意乙個節點,將它當做根節點,返回此節點的最大盜取金額。比如上一張中的4,如果傳遞的節點是4,那我們要返回的就是以4為根節點,小偷在以4為根節點的樹上,能盜取的最大金額是多少,當然為了便於理解,3,5,1節點可以捨棄不看。有了這樣的思路,我們來編寫程式。

public

introb

(treenode root)

//因為小偷不能連續盜竊,所以如果偷根節點,那麼根節點的左右子樹就不能偷所以分成兩類

//一類:根節點+根節點的孫子節點 另一類:根節點的兒子節點

int left=0;

//計算以根節點的左孫子節點為根節點,小偷能盜取的最大值

int right=0;

//計算以根節點的右孫子節點為根節點,小偷能盜取的最大值

//計算根節點和根節點左右子樹的子樹

if(root.left!=null)

if(root.right!=null)

int sum1=root.val+left+right;

//維護的就是根節點加根節點的左右孫子節點

int sum2=

rob(root.left)

+rob

(root.right)

;//維護的就是根節點的左右兒子節點能獲取的最大值

return sum1>sum2?sum1:sum2;

//返回最大值

}

再次強調,必須要定義好遞迴函式的功能,**rob(root.left.left)**返回的就是以根節點的左孩子的左孩子為根節點小偷能盜取的最大值,定義遞迴函式功能尤其重要。

畫張圖就能更好地理解了:

不過上面的遞迴時間複雜度是有點高的,大家可以想想,以某個節點為根節點,那麼能盜取的最大金額是固定的,所以我們可以維護乙個hashmap來做備忘錄。**就不寫了,很簡單,和第一題的備忘錄幾乎一樣,大家可以動手試試。

遞迴函式在我看來最重要的是要定義遞迴函式的功能,這個最為重要,其次就是要明白遞迴是乙個不斷重複的子過程。不過我們也可以在此基礎上畫圖來更加深入地理解遞迴。舉個簡單的例子,如何用遞迴求乙個陣列的最大值?我們可以將陣列一分為2,左邊求最大值,右邊求最大值,然後比較返回,此時的遞迴函式功能是啥?就是給你乙個陣列中的指定範圍,求出指定範圍的陣列最大值。我們可以舉個簡單例子,比如只有4個元素的陣列,可以進行畫圖來更加深入的理解上面的遞迴思想。不過話說回來,每個人都有每個人的看法,大家可以多思考,可以按照文章中提出的方法多寫幾道遞迴的題目,總有一天會讓你感受到遞迴的思想。遞迴是很強大的,比如我們使用的排序,例如歸併排序,快速排序都離不開遞迴。

這邊可以稍微提一下兩個排序的思想:歸併排序就是將陣列一分為2,左邊先排好序,右邊排好序,然後再合併。那歸併排序的遞迴函式功能是什麼呢?就是排序。我們要做的就是先將陣列一分為2,左半部分呼叫遞迴有序,右半部分呼叫遞迴有序,我們最後要做的就是將兩個有序陣列合併成乙個有序陣列。

那麼快速排序的怎麼理解呢?快速排序涉及到荷蘭國旗問題,就是隨機選取乙個數,將陣列中小於這個數的數字放在左邊,大於這個數的數字放在右邊,接著再對左右兩邊繼續遞迴。這兩個排序加堆排序我也會進行整理總結,畢竟他們在面試中經常被提問,還是比較重要的。

如何才能寫出好的產品文件

一般來說,產品文件分為產品需求文件和產品使用文件兩種。產品需求文件主要面向的是產品的開發 設計者,期望是產品的實際開發人員了解產品的細節,讓開發完成的產品達到前期設計需求的預期 產品使用文件面向的主要是使用者,使其通過產品文件掌握產品的功能使用,也就是我們常說的產品使用幫助 如果不搞清楚文件面向的物...

如何寫出好函式

寫 和寫別的東西很像。在寫 或文章時,你先想什麼就寫什麼,然後再打磨它。初稿也許粗陋無序,你就斟酌推敲,直至達到你心目中的樣子。我寫函式時,一開始都冗長而複雜。有太多縮排和巢狀迴圈。有過長的引數列表。名稱是隨意取的,也會有重複的 不過我會配上一套單元測試,覆蓋每行醜陋的 然後我會打磨這些 分界函式 ...

如何才能建立起似然函式

函式形式表達 p y 0 w,x 1 g z p y 1 w,x g z p 正確 到這裡,我們得到乙個回歸函式,它不再像y wt x一樣受離群值影響,他的輸出結果是樣本 為正例的概率 0到1之間的小數 我們接下來解決第二個問題 選定乙個閾值.似然函式是如下式子的連乘 下面的2分類是個個例 似然 連...