您的位置:首页 > 其它

从暴力递归到动态规划的转换(推荐)

2017-09-06 22:16 369 查看

从暴力递归到动态规划

给一串数字,返回其能否转换成IP地址形式(IP地址的正确形式)。
如110.125.10.5

int P(i,p)
假设0...i-1都已经转成合法的IP段了,组成的IP段数是p个。
则有:

递归版本:
/**
* Created by YangGang on 2017/9/6.
*/
public class ConvertStringToIP {

public static int convertNum1(String str){
//IP地址包括的数字个数范围在4~12
if(str==null||str.length()<4||str.length()>12){
return 0;
}
char [] chars=str.toCharArray();
return process(chars,0,0);
}

public static int process(char [] chars,int i,int parts){
//终止条件,一个是遍历结束,另一个是划分大于4部分,而IP只有4部分排除
if(i>chars.length||parts>4){
return 0;
}
//终止条件:已经到了结尾,看看是否正好分成4部分,若正好分成4部分则成功,否则失败
if(i==chars.length){
return parts==4?1:0;
}
//如果把自己作为一个部分,合法的个数
int res=process(chars,i+1,parts+1);
//如果当前字符是0,只能够把当前自己作为一段,因为IP中不可能出现012这种情况
if(chars[i]=='0'){
return res;
}
//如果当前字符不是0,则有可能是当前字符和下一字符一起构成一个部分。
res+=process(chars,i+2,parts+1);
//当前字符不是0,和下两个字符一起构成一部分,注意IP一个段只能是0-255
if(i+2<chars.length){
int sum=(chars[i]-'0')*100+(chars[i+1]-'0')*10+(chars[i+2]-'0');
if(sum<255)
{
return res+process(chars,i+3,parts+1);
}
else {
return res;
}
}
else {
return res;
}
}
}


递归:

第一步:了解BaseCase(不需要依赖任何,自己就知道自己的值)

第二步: 建立上下文关系

第三步:找好递归出口(边界条件)

递归改写:

首先看process(char [] chars,int i,int parts)函数

如果i和parts确定了,返回值就确定了。

所以可以建立一个二维表:(i,parts---唯一的返回值)

自然要关注parts的取值,parts的空间可以开成6个:0,1,2,3,4,>4(5) ;

i的取值[0,n+2]。

则二维表如下:

   0 1 2 3 4 5

0

1

2

.

.

.

n-1

n

n+1

n+2

(0,0)可能依赖(1,1)、(2,1)、(3,1)



先确定最右边的值,之后就从右边往左来。

然后从BaseCase转化,先填写好。



填写好后,再按照递归指示顺序把表剩余部分填写完毕。

从下往上,从右往左填写。



实际上并不需要都去填写。



看看哪些位置是不用算的,在for循环中控制一下,可以进一步减少计算。

改写成的DP代码如下:

public static int convertNum2(String str){
if(str==null||str.length()<4||str.length()>12){
return 0;
}
char [] chars=str.toCharArray();
int size=chars.length;
int [][]dp=new int [size+3][5];
//初始值
dp[size][4]=1;
for(int parts=3;parts>=0;parts--){
//因为IP每个段最多3位(i=Math.min(size-1,parts*3))
for(int i=Math.min(size-1,parts*3);i>=parts;i=Math.min(i-1,parts*3)){
dp[i][parts]=dp[i+1][parts+1];
if(chars[i]!=0){
dp[i][parts]+=dp[i+2][parts+1];
if(i+2<chars.length){
int sum=(chars[i]-'0')*100+(chars[i+1]-'0')*10+(chars[i+2]-'0');
if(sum<256){
dp[i][parts]+=dp[i+3][parts+1];
}
}
}
}
}
return dp[0][0];
}








先算第3列,再算第2列,然后算第1列,最后算第0列。

刨除那些不需要算的,



因为p是有限的,所以可以蜕化为O(n)

所以把递归转换成动态规划的步骤是:

第一步:确定解空间

第二步:看看哪些事都不依赖的(BaseCase)设好值

第三步:看看哪个状态是所求的状态

最后一步:确定计算顺序

具体到dp的决策,把递归中的决策抄下来就行了。





                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息