日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何才能轻而易举的写出递归函数

發布時間:2025/3/19 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何才能轻而易举的写出递归函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

先說下我的學習方式吧

首先,我想說下我的學習方式,每個人的學習方式都是不同的,有的人悟性比較高,所以學東西比較快,但也有一部分人,學東西比較慢,哈哈,我就是那學東西比較慢的那一部分人。但我也不氣餒,認真踏實的學就可以了,千萬不能浮躁。
所以在我學習算法的過程中,首先要搞懂這個技術是來解決什么問題的,這是很重要的一步,其次如何使用,最后它的原理是什么。走好這三步我覺得這個技術你也就學會了。

遞歸

首先第一步,遞歸這個算法是用來解決什么問題的或者主要用于什么方向的。在我目前的理解,遞歸主要是將一個大問題分解成小問題,最后各個小問題的解再進行合并。這就是遞歸的主要作用。

注意兩個技巧來編寫遞歸函數:

  • 1.思考這個問題能否分解成小問題
  • 2.遞歸函數的編寫在我看來最重要的是定義遞歸函數的功能,不要太糾結遞歸函數是怎么運行的,這么思考會陷入死胡同的,我之前也是糾結這塊,弄得頭疼。

做幾道題目吧(leetcode 343,leetcode 337)

leetcode 343:給定一個正整數 n,將其拆分為至少兩個正整數的和,并使這些整數的乘積最大化。 返回你可以獲得的最大乘積。

實例:輸入: 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 int help(int num){ //返回一個傳遞的正整數num的乘積最大化得結果if(num==2){ //這是臨界條件,大家可以動下腦筋就能思考出來了,當時2的時候,只能拆分成1+1return 1;}int res=0;for(int i=1;i<num;i++){//將num拆分成i和num-iint a=i*help(num-i);//num-i是不是又可以拆分成多個數字之和,//那我們在將num-i傳遞到遞歸函數中即可,不要忘記遞歸函數的功能是返回一個//正整數的乘積最大化的結果,所以我們只需要從i遍歷到num-1,求出最大值即可int b=i*(num-i); //這邊代碼是什么意思呢?比如10分成【1,9】,9的確可以再分,但我不分9了,//直接兩個數相乘求乘積也可以吧,這題的總體思想就是遞歸,遞歸中也包含分與不分兩個方面res=Math.max(res,Math.max(a,b)); //比較a和b兩個最大值,再和res比較得出res結果}return res; }

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

HashMap<Integer,Integer> map=new HashMap<>(); public int help(int num){ if(num==2){ return 1;}//主要添加了下面三行代碼,你們想要,我求出了10的最大化,//是不是要進行保存起來,因為10的最大化是一個固定值,不是變化的,所以當再用到10這個正整數的時候//就無須再進行計算了,直接返回他的結果就可以了if(map.containsKey(num)){return map.get(num);}int res=0;for(int i=1;i<num;i++){//將num拆分成i和num-iint a=i*help(num-i);int b=i*(num-i); res=Math.max(res,Math.max(a,b)); }//將num這個正整數的最大化乘積res進行保存map.put(num,res);return res; }

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

接著再來一題,

leetcode 337:在上次打劫完一條街道之后和一圈房屋后,小偷又發現了一個新的可行竊的地區。這個地區只有一個入口,我們稱之為“根”。 除了“根”之外,每棟房子有且只有一個“父“房子與之相連。一番偵察之后,聰明的小偷意識到“這個地方的所有房屋的排列類似于一棵二叉樹”。 如果兩個直接相連的房子在同一天晚上被打劫,房屋將自動報警。

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


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

public int rob(TreeNode root){ //定義函數功能:以某個節點為根,返回小偷能盜取的最大值if(root==null){ //當節點為空,返回0,初始條件return 0;}//因為小偷不能連續盜竊,所以如果偷根節點,那么根節點的左右子樹就不能偷所以分成兩類//一類:根節點+根節點的孫子節點 另一類:根節點的兒子節點int left=0; //計算以根節點的左孫子節點為根節點,小偷能盜取的最大值int right=0; //計算以根節點的右孫子節點為根節點,小偷能盜取的最大值//計算根節點和根節點左右子樹的子樹if(root.left!=null){left=rob(root.left.left)+rob(root.left.right);}if(root.right!=null){right=rob(root.right.right)+rob(root.right.left);}int sum1=root.val+left+right;//維護的就是根節點加根節點的左右孫子節點int sum2=rob(root.left)+rob(root.right);//維護的就是根節點的左右兒子節點能獲取的最大值return sum1>sum2?sum1:sum2; //返回最大值}

再次強調,必須要定義好遞歸函數的功能,**rob(root.left.left)**返回的就是以根節點的左孩子的左孩子為根節點小偷能盜取的最大值,定義遞歸函數功能尤其重要。
畫張圖就能更好地理解了:

不過上面的遞歸時間復雜度是有點高的,大家可以想想,以某個節點為根節點,那么能盜取的最大金額是固定的,所以我們可以維護一個HashMap<TreeNode,Integer>來做備忘錄。代碼就不寫了,很簡單,和第一題的備忘錄幾乎一樣,大家可以動手試試。

總結:

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

這邊可以稍微提一下兩個排序的思想:歸并排序就是將數組一分為2,左邊先排好序,右邊排好序,然后再合并。那歸并排序的遞歸函數功能是什么呢?就是排序。我們要做的就是先將數組一分為2,左半部分調用遞歸有序,右半部分調用遞歸有序,我們最后要做的就是將兩個有序數組合并成一個有序數組。

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

這是我第一次寫博客,可能有些語句不通順或者邏輯不通,還請大家見諒,也希望大家能多多留言,我們一起進步。

總結

以上是生活随笔為你收集整理的如何才能轻而易举的写出递归函数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。