遞歸同迭代一樣是很多算法的實現方式,比如dfs-深度優先搜索。尤其在樹這種結構中應用最爲廣泛。下面是本人從力扣中選出的一些題目,通過遞歸題目的總結完成對遞歸的掌握。
題目1:二叉樹的最近公共祖先
思路
通過題目可以看到,在樹結構中,遞歸需要考慮的就三個根節點,左子樹,右子樹,此題根據題目有如下思路:
- 先分情況:根節點等於其中p或者q時,公共祖先是根節點;
- 考慮完根節點,再考慮子樹,如果p和q都在左子樹或者都在右子樹,則p或者q爲公共祖先;
- 一個在左子樹,一個在右子樹,則根節點爲公共祖先。
實現如下:
a.寫邊界條件——遞歸到該節點的時候怎麼處理:意思爲遞歸到該節點的時候,如果等於其中一個節點就獲取;
if(root==null||root==p||root==q){
return root;
}
b.遍歷不用說了,左右子樹遍歷;
TreeNode leftNode=lowestCommonAncestor( root.left, p, q);
TreeNode rightNode=lowestCommonAncestor( root.right, p, q);
c.該遞歸是隻獲取到p或者q其中一個就返回了,所以還需要有後續處理
如果左子樹爲空,說明p和q都在右子樹;如果右子樹爲空,說明p和q都在左子樹;如果一左一右,則返回root;
if(leftNode==null) return rightNode;
if(rightNode==null) return leftNode;
return root;
合起來就是
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//邊界條件:到此結束,給我回去;
if(root==null||root==p||root==q){
return root;
}
TreeNode leftNode=lowestCommonAncestor( root.left, p, q);
TreeNode rightNode=lowestCommonAncestor( root.right, p, q);
if(leftNode==null) return rightNode;
if(rightNode==null) return leftNode;
return root;
}
}
題目2:1~n整數中1出現的次數
思路
列個表格意思就很清楚了,表格如下
範圍 | 1的個數 |
---|---|
1~9 | 1 |
10~19 | 10+1 |
20~29 | 1 |
… | … |
90~99 | 1 |
範圍 | 1的個數 |
---|---|
1~99 | 20 |
100~199 | 120 |
200~299 | 20 |
… | … |
900~999 | 20 |
我們來看12中1的個數是由哪些部分組成:
1.1~9中1的個數
2.10~19中首位1的個數;
3.個位1~2的個數;
再來看156中1的組成個數:
1.1~99中1的個數
2.100~199中首位1的個數;
3.剩餘數字0~56中1的個數;
4.不難發現,56又可以拆爲1~9中1的個數*5+10-19中首位1的個數 +6中1的個數;
依次類推,不難發現明顯就是遞歸的思想;
具體思路如下
- 用pow代表當前數字的位數;
String s=n+"";
int l=s.length();
int pow=((int)Math.pow(10,l-1));
- 用high代表當前數的首尾;
int high=s.charAt(0)-'0';
- 用last代表除了首位以外剩下的數字
int last=n%pow;
4.分兩種情況
a.假設f(n)爲1~n中1的個數,首位爲1:則1的個數的組成方式爲 f(pow-1)+(首位1的個數:last+1 ) + 剩餘數字中1的個數:f(last)
b.首爲不爲1:也不難推斷
代碼如下
class Solution {
int sum=0;
public int countDigitOne(int n) {
return f(n);
}
public int f(int n){
//邊界條件
if(n<=0) return 0;
String s=n+"";
int l=s.length();
int pow=((int)Math.pow(10,l-1));
int high=s.charAt(0)-'0';
int last=n%pow;
if(high==1){
return f(pow-1)+f(last)+last+1;
}
else{
return high*f(pow-1)+f(last)+pow;
}
}
}