递归
描述:递归是一种解决问题的方法,它解决问题的各个小部分,直到解决最初的大问题。通常涉及函数直接或间接调用自身。
每个递归函数都必须要有边界条件,即一个不在递归调用的条件(停止点),以防止无限递归。如果忘记加递归调用的边界条件,递归并不会无限制的执行下去,浏览器会抛出错误,也就是所谓的栈溢出错误。
斐波那契数列
function fibonacci(num){
if(num==1||num==2){//停止条件
return 1;
}
return fibonacci(num-1)+fibonacci(num-2);
}
动态规划
描述:是一种将复杂问题分解为更小的子问题(相互依赖的子问题)来解决的优化技术。
动态规划的三个步骤:
1、定义子问题
2、实现要反复执行而解决子问题的部分
3、识别并求解出边界条件
背包问题:给出一组项目,各自有值和容量,目标是找出总值最大的项目集合。这个问题的限制是,总容量必须小于等于“背包”的容量
最长公共子序列:
矩阵链相乘:
硬币找零:
图的全源最短路径:
例子:最少硬币找零问题
function MinCoinChange(coins){
var coins = coins;//数组,零钱种类
var cache ={};
this.makeChange=function(amount){//找零的方法,amount为找零钱的总数
var me =this;
if(!amount){//amount为0的时候直接返回空数组
return [];
}
if(cache[amount]){//用cache存入最优解,如果有最优则返回,没有则执行算法
return cache[amount];
}
var min=[],newMin,newAmount;
for(var i=0;i<coins.length;i++){
var coin = coins[i];//选取当前零钱值
newAmount=amount-coin;//选取后剩余零钱总数
if(newAmount>=0){//剩余钱数大于等于0,则继续递归
newMin=me.makeChange(newAmount);
}
if(newAmount>=0&&(newMin.length<min.length-1||!min.length)&&(newMin.length||!newAmount)){
min=[coin].concat(newMin);//给数组添加值
console.log('new Min'+min+'for'+amount);
}
}
return (cache[amount]=min);
}
}
var minCoinChange = new MinCoinChange([1,5,10,25])
console.log(minCoinChange.makeChange(36));
贪心算法
描述:是一种近似解决问题的技术,期盼通过每个阶段的局部最优选择,从而达到全局最优(全局最优解)。它不像动态规划那样计算更大的格局。
function MinCoinChange(coins){
var coins=coins;
this.makeChange=function(amount){
var change=[],
total=0;
for(var i=coins.length;i>=0;i--){
var coin=coins[i];
while(total+coin<=amount){
change.push(coin);
total+=coin;
}
}
return change;
}
}
var minCoinChange = new MinCoinChange([1,5,10,25])
console.log(minCoinChange.makeChange(36));
比起动态规划,贪心算法更简单,更快。然而,它并不总是能得到最优解。但综合来看,他相对执行时间来说,输出了一个可以接受的解。