TIP
递归只要找对递归边界和递归条件(也可以传入引用类型 不设置递归边界)
- 一个问题的解可以分解为多个子问题的解
- 这个问题和分解之后的子问题,除了数据规模不同,求解思路完全一样
- 存在基线/终止条件
一般情况下递归可以用迭代循环实现
# 1-100的和
正常for循环
let result = 0; for (let i = 0; i <= 100; i++) { result += i; } console.log(result)递归
// 方法一 function add(sum, num) { sum += num; num++; if(num > 100) { return sum; } else { return add(sum, num) } } console.log(add(0, 1)) // 方法二--奇怪思路--少考虑 设置上边界 function add(num) { if (num === 100) return num; return num + add(num + 1) } add(0) // 5050 //方法三--- 设置下边界 ---一般思考是这种 function add(n) { if (n == 1) return 1; return n + add(n - 1) } console.log(add(100))尾递归
function add(num, total) { if (num > 100) return total; return add(num + 1, num + total) } const sum = add(1, 0) console.log(sum)优化实现
function add(n) { add.m = add.m || Object.create(null); if(add.m[n]) return add.m[n]; if(n === 1) { return 1; } else { return add.m[n] = add(n - 1) + n } }
# 乘积
- 普通递归函数调用会产生"调用记录"存放栈中,当有函数返回,对应的调用记录才会消失,上述用普通调用执行中,不断调用自身导致一直没有返回,这样就不断的在栈中存储调用,多次删除溢出
function fac(n){ if (n === 1) return 1; return n*fac(n - 1) } - 尾调用永远只有一个调用记录,调用函数生成一个调用记录,最后一步操作 return fac(n - 1, n * total)把当前函数计算结果当做参数传递给下一个自身调用,这样一个函数调用记录就消失了,因此执行完了不会溢出
function fac(n, total) { if (n == 1) return total; return fac(n - 1, n * total) }