递归同迭代一样是很多算法的实现方式,比如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;
}
}
}