动态规划:通常基于一个递推公式及一个或多个初始状态,当前子问题的解将由上一个子问题的解推出
基本思想:要解决一个给定的问题,我们需要解决其不同部分(即解决子问题),再合并子问题的解以得出原问题的解,通常子问题非常相似,为此动态规划视图只解决每个子问题一次,从而减少计算量,一旦某个给定子问题的解已经算出来,则将其记忆储存,以便下次需要同一个子问题解值时直接查表
1》斐波那契数列
方法一:递归调用
function feibonaqi(n){
return n<2?n:feibonaqi(n-1)+feibonaqi(n-2);
}
console.log(feibonaqi(5));//5 最多能达到40左右
尾调调用斐波那契数代码改进
function feibonaqie(n,ac1=1,ac2=1){
return n<2?ac2:feibonaqie(n-1,ac2,ac1+ac2);
}
console.log(feibonaqie(1000));//可以输入数字大概到1000
方法二:备忘录算法
var map=new Map();
function feibonaqi(n){
if(n<2) return n;
if(map.has(n)){
return map.get(n);
}
var value=feibonaqi(n-1)+feibonaqi(n-2);
map.set(n,value);
return value;
}
console.log(feibonaqi(5));//5
方法三:
function feibonaqi(n){
if(n<2) return n;
var a=1,b=1;
var temp=a+b;
for(var i=3;i<=n;i++){
temp=a+b;
a=b;
b=temp;
}
return temp;
}
console.log(feibonaqi(5));//5 能达到1000
2》爬楼梯问题
方法一:递归求解,时间复杂度0(2^n)
根据递归公式
f(n)=f(n-1)+f(n-2); f(1)=1; f(2)=2
function getways(n){
if(n<1) return 0;
if(n==1) return 1;
if(n==2) return 2;
return getways(n-1)+getways(n-2);
}
var n=4;
console.log(getways(n));//5
方法二:把重复的值记录下来使用备忘录算法,时间复杂度0(n),空间复杂度0(n)
var map=new Map();
function getways(n){
if(n<0) return 0;
if(n==1) return 1;
if(n==2) return 2;
if(map.has(n)){
return map.get(n)
}
var value=getways(n-1)+getways(n-2);
map.set(n,value);
return value;
}
console.log(getways(4));
方法三:正常思路从下往上走,可以看出每次迭代只需要前两次迭代的数据,时间复杂度O(n),但是空间复杂度0(1)
function getways(n){
if(n<0) return 0;
if(n==1) return 1;
if(n==2) return 2;
var a=1,b=2;
var temp=a+b;
for(var i=3;i<=n;i++){
temp=a+b;
a=b;
b=temp;
}
return temp;
}
console.log(getways(1000));
3》求连续子数组中最大和
思路:动态规划
遍历数组,遇到负的和则放弃之前的结果,重新积累,这期间保留最大值
用max记录最终返回的最大和,用curmax记录累加值
对于数值中一个数arr[i],若其左边的累加和非负,那么加上arr[i]
判断此时的curmax是否大于max,若大于此时的max,则用max记录下来
function FindGreateSum(arr){
var len=arr.length;
var curmax=0;
var max=0;
var start=0;
var end=0;
//数组中正负数都有
for(var i=0;i<len;i++){
curmax+=arr[i];
if(curmax<0){
curmax=0;
}
if(curmax>max){
max=curmax;
}
}
return max;
}
var arr=[2,4,-7,5,2,-1,2,-4]
console.log(FindGreateSum(arr));