基础算法之美
递归
递归是一种应用非常广的一种算法.后面涉及的DFS 深度优先搜索、前中后序二叉树遍历等都是用递归算法计算
举个简答的例子理解什么是递归
现在很多 App 都有这个功能“推荐注册返佣金”。 这个功能中,用户 A 推荐用户 B 来注册,用户 B 又推荐了用户 C 来注册。我们可以说,用户 C 的“最终推荐人”为用户 A,用户 B 的“最终推荐人”也为用户 A,而用户 A 没有“最终推荐人”。 问题:那么如何计算C的最终推荐人呢? 一般设计的sql结构是这样的
actor_id 表示用户 id,referrer_id 表示推荐人 id。 解答:为了能找到最终推荐人,需要首先使用C找到他的“上级推荐人”B,再用B找到他的“上级推荐人”A.然后发现A并没有“上级推荐人”,那么A就是“最终推荐人”
所以这种重复执行一个子操作获取一个父结果的方式就叫做递归 递归公式:
f(n)=f(n-1)+1 其中,f(1)=1
递归的三个条件
- 一个问题的解可以分解为几个子问题的解:“获取上级推荐人”
- 这个问题与分解之后的子问题,除了数据规模不同,求解思路完全一样:“C获取上级推荐人和B获取上级推荐人操作是一样的”
- 存在递归终止条件:“A没有上级推荐人”
代码实现递归
int f(int n) {
if (n == 1) return 1;
if (n == 2) return 2;
return f(n-1) + f(n-2);
}
防止堆栈溢出的实现方式
// 全局变量,表示递归的深度。
int depth = 0;
int f(int n) {
++depth;
if (depth > 1000) throw exception;
if (n == 1) return 1;
return f(n-1) + 1;
}
防止重复计算 比如获取f(4)需要获取f(2),获取f(3)也需要获取f(2)这个时候就可以不用计算f(2)而是直接使用其他的方式获取.
public int f(int n) {
if (n == 1) return 1;
if (n == 2) return 2;
// hasSolvedList可以理解成一个Map,key是n,value是f(n)
if (hasSolvedList.containsKey(n)) {
return hasSolvedList.get(n);
}
int ret = f(n-1) + f(n-2);
hasSolvedList.put(n, ret);
return ret;
}
编写递归代码的姿势
- 推导递归公式(数学基础)
- 找出最终条件
- 编写递归代码
附
1. 获取最终推荐人
long findRootReferrerId(long actorId) {
Long referrerId = select referrer_id from [table] where actor_id = actorId;
if (referrerId == null) return actorId;
return findRootReferrerId(referrerId);
}