递归观点
递归是一种针对简朴轮回难以编程完成的题目,经由过程函数挪用本身,供应文雅处理方案的手艺。
递归都具有以下三个要点:
运用 if-else 或 switch 语句来指导差别的状况。
具有基本状况(base case)或住手前提(stopping condition)来住手递归。
每次递归挪用都邑简化原始题目,让它不停靠近基本状况,所以能够用差别的参数挪用本身要领,直到它变成这类基本状况。这个称之为递归挪用(recursive call)。
示例,盘算阶乘
if(n == 0){ // base case
return 0;
}else { // recursive call
return n * factorial(n-1)
}
递归的上风--斐波那契数列
盘算阶乘很轻易运用轮回改写,某些状况下,用轮回不轻易处理的题目能够应用递归给出一个直观简朴的解法。
斐波那契数列从 0 到 1 最先,以后的每个数都是序列中的前两个数之和,经由过程递归能够简朴的完成出来。
var count = 0;
function fib(n) {
count++;
if(n == 0){
return 0;
}else if(n == 1){
return 1;
}else {
return fib(n-1) + fib(n-2);
}
}
const result = fib(10);
console.log('result',result);
console.log('count',count);
// result 55
// count 177
顺序中会涌现许多反复挪用,求第 10 个斐波那契数,就挪用了 177 次本身函数,假如尝试求出更大的斐波那契数,那末响应的挪用次数就会急剧的增添。
优化递归挪用
将盘算过的斐波那契值存起来,能够优化递归挪用。经由过程改进,求第 10 个斐波那契数,只挪用的 11 次本身函数。而且挪用本身函数的次数永远是,n + 1 次,n 代表第 n 个需求的斐波那契数。
var count = 0;
const calculated = [];
function fib(n) {
count++;
if(n == 0){
return 0;
}else if(n == 1){
return 1;
}else {
if(!calculated[n-1]){
calculated[n-1] = fib(n-1);
}
if(!calculated[n-2]){
calculated[n-2] = fib(n-2);
}
return calculated[n-1] + calculated[n-2];
}
}
const result = fib(10);
console.log('result',result);
console.log('count',count);
// result 55
// count 11
递归辅佐要领
有时候能够经由过程找到一个要处理的初始题目的相似题目,来找到初始题目的处理方案。这个相似的要领称之为递归辅佐要领。
举例,假如一个字符串从左读和从右读都是一样的,那末他就是一个回文串(palindrome)。能够经由过程下面的函数推断。
function palindrome(str) {
if(str.length <= 1 ){
return true;
}else if(str[0] !== str[str.length - 1]){
return false;
}else {
return palindrome(str.slice(1,-1));
}
}
const result = palindrome("dddddd");
console.log(result); // ture
每次挪用 palindrome 要领时,都邑运用 str.slice 来建立一个新的字符串。
为了防止从新建立字符串,运用递归辅佐要领 isPalindrome 来举行改进。
function isPalindrome(str) {
return palindrome(str,0,str.length-1);
}
function palindrome(str,low,high) {
if(low >= high){
return true;
}else if(str[low] !== str[high]){
return false;
}else {
low ++;
high --;
return palindrome(str,low,high);
}
}
const result = isPalindrome("dddaaaerddd");
console.log(result); // false