之前一直很惧怕递归,但是写了几次递归之后好像突然就懂了它的思想。
关于递归,也就是把问题一步步分解成最小部分直到最小的部分可以解决即可(也就是递归结束的条件)。
其实很像数学表达式fn=fn-1+fn-2之类,这类的递归很好写。(感觉动态规划就是递归相反的另一种,递归是自上而下,而动态规划是自下而上)
比如说这一题:
给定一个数字,按照如下规则翻译成字符串:0翻译成“a”,1翻译成“b”...25翻译成“z”。一个数字有多种翻译可能,例如12258一共有5种,分别是bccfi,bwfi,bczi,mcfi,mzi。实现一个函数,用来计算一个数字有多少种不同的翻译方法。
这一题用递归思想就很好解决,可以把n种不同的翻译方法看成fn,那么fn就等于fn-1或fn-2+fn-1(取决于前两位数字是否小于26)
那么我们就可以直接写出来:
if(Number(num.toString()[0]+num.toString()[1])<=25){
return sort(Number(num.toString().slice(2,n)),n-2)+sort(Number(num.toString().slice(1,n)),n-1)
}
else{
return sort(Number(num.toString().slice(1,n)),n-1)
}
然后写截止条件,即什么时候就不需要递归,直接就可以得到答案了呢?答案是在数字位数为1位或2位的时候,当递归到数字位数只有1位的时候毫无疑问只有1种翻译方法,2位的时候判断一下是否小于26,是的话2种,不是1种。
if(n==1){
return 1
}
if(n==2){
if(Number(num.toString()[0]+num.toString()[1])<=25){
return 2
}else{
return 1
}
}
要注意递归的终止条件要放在开头。
最后我们还需要一个主函数来调用它。所以整体代码如下:
function main(num){
var n=num.toString().length;
return sort(num,n);
}
function sort(num,n){
if(n==1){
return 1
}
if(n==2){
if(Number(num.toString()[0]+num.toString()[1])<=25){
return 2
}else{
return 1
}
}
if(Number(num.toString()[0]+num.toString()[1])<=25){
return sort(Number(num.toString().slice(2,n)),n-2)+sort(Number(num.toString().slice(1,n)),n-1)
}else{
return sort(Number(num.toString().slice(1,n)),n-1)
}
}
动态规划我感觉就是递归的逆向思维,递归是自上而下的,而DP是自下而上一步步推上去的。
下面是我摘录的一段,还没好好看DP,有空整理个DP的专栏。
自下而上,动态规划,从最小的问题开始 :
f(r)表示以r为开始(r最小取0)到最右端所组成的数字能够翻译成字符串的种数。对于长度为n的数字,f(n)=0,f(n-1)=1,求f(0)。
递推公式为 f(r-2) = f(r-1)+g(r-2,r-1)*f(r);
其中,如果r-2,r-1能够翻译成字符,则g(r-2,r-1)=1,否则为0。
因此,对于12258:
f(5) = 0
f(4) = 1
f(3) = f(4)+0 = 1
f(2) = f(3)+f(4) = 2
f(1) = f(2)+f(3) = 3
f(0) = f(1)+f(2) = 5