力扣解题思路:91. 解码方法

91. 解码方法


思路:给定一个数字,按照如下规则翻译成字符串:1 翻译成“a”,2 翻译成“b”… 26 翻译成“z”。一个数字有多种翻译可能,例如 12258 一共有 5 种,分别是 abbeh,lbeh,aveh,abyh,lyh。实现一个函数,用来计算一个数字有多少种不同的翻译方法。

这一题用递归还是蛮简单的,就是耗时比较长,对于“0”的判断要仔细:

public int count = 0;
public int numDecodings(String s) {
     
    if(s.equals("0")) return 0;
    dfs(s,0);
    return count;
}
public void dfs(String s,int start){
     
    if(start == s.length()){
     
        count++;
        return;
    }
    if(s.charAt(start) != '0'){
     
        dfs(s,start + 1);
    }else{
     
        return;
    }
    if(start + 1 < s.length()){
     
        int sum = (s.charAt(start) - '0')*10 + s.charAt(start+1) - '0';
        if(s.charAt(start) != '0' &&  sum > 0 && sum < 27){
     
            dfs(s,start + 2);
        }
    }
}

其实做了这么多题是可以发现递归和动态规划是有相似互通的地方的,比如我改一下这个递归应该就可以看出来了:

public int digui(String s, int start) {
     
    if (s.length() == start) {
     
        return 1;
    }
    if (s.charAt(start) == '0') {
     
        return 0;
    }
    int ans1 = digui(s, start + 1);
    int ans2 = 0;
    if (start < s.length() - 1) {
     
        int ten = (s.charAt(start) - '0') * 10;
        int one = (s.charAt(start + 1) - '0');
        if (ten + one <= 26) {
     
            ans2 = digui(s, start + 2);
        }
    }
    return ans1 + ans2;
}

可以看出递归的递推式应该是如果index的后两位小于等于26, digui(s, start) = digui(s, start+1)+digui(s, start+2)
否则
digui(s, start) = digui(s, start+1)
将其转为动态方程就是:

if ((s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0') <= 26) {
     
    dp[i] = dp[i + 1] + dp[i + 2];
} else {
     
    dp[i] = dp[i + 1];
}

因为我们是从后往前更新dp数组,所以注意初始化:

dp[len] = 1;
if (s.charAt(len - 1) == '0') {
     
    dp[len - 1] = 0;
} else {
     
    dp[len - 1] = 1;
}

完整代码如下:

public int numDecodings(String s) {
     
    if (s == null || s.length() == 0) {
     
        return 0;
    }
    int len = s.length();
    int[] dp = new int[len + 1];
    dp[len] = 1;
    if (s.charAt(len - 1) == '0') {
     
        dp[len - 1] = 0;
    } else {
     
        dp[len - 1] = 1;
    }
    for (int i = len - 2; i >= 0; i--) {
     
        if (s.charAt(i) == '0') {
     
            dp[i] = 0;
            continue;
        }
        if ((s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0') <= 26) {
     
            dp[i] = dp[i + 1] + dp[i + 2];
        } else {
     
            dp[i] = dp[i + 1];
        }
    }
    return dp[0];
}

但是往往在进行动态数组的更新的时候,我不太喜欢从后往前更新,那么这一题可不可以从前往后更新呢?当然可以呀,但是我最开始作死非要把动态规划数组设置成长为s.length(),所以导致后续出现了很多奇奇怪怪的问题,所以遇到字符串
还是老老实实把数组长度设置为s.length()+1吧:

public int numDecodings(String s) {
     
    if (s == null || s.length() == 0)
        return 0;
    int n = s.length();
    int[] dp = new int[n + 1];
    dp[0] = 1;
    if(s.charAt(0) == '0') return 0; 
    dp[1] = 1;
    for (int i = 2; i <= n; i++) {
     
        int one = Integer.valueOf(s.substring(i - 1, i));
        if (one != 0)
            dp[i] += dp[i - 1];
        if (s.charAt(i - 2) == '0')
            continue;
        int two = Integer.valueOf(s.substring(i - 2, i));
        if (two <= 26)
            dp[i] += dp[i - 2];
    }
    return dp[n];
}

你可能感兴趣的:(力扣解题思路:91. 解码方法)