动态规划:数字字符串转换为字母字符串有多少种转换结果

题目

规定 1 和 A 对应、2 和 B 对应、3 和 C 对应… 26 和 Z 对应。

那么一个数字字符串比如 “111” 就可以转化为:“AAA”、“KA” 和 “AK”。

给定一个只有数字字符组成的字符串 str,返回有多少种转化结果。

分析

暴力递归

从左往右的尝试模型。

public class CovertToLetterString {
    //str 只含有数字字符0~9
    //返回多少种转化方案
    public static int number(String str) {
        if (str == null || str.length == 0)
            return 0;
        return process(str.toCharArray(), 0);
    }
    
    //str[0..i-1] 转化无需过问
    //str[i...] 去转化,有多少种转化方法
    public static int process(char[] str, int i) {
        if (i == str.length) {
            return 1; //之前的字符已经转换了一种结果
        }
        
        //i没到最后,说明有字符
        if (str[i] == '0') { //0不对应任意一个字符,如果出现0单独的情况,说明之前做过的决定错了 (如105)
            return 0;
        }
        //str[i] != '0'
        //可能性1:i单转
        int ways = process(str, i + 1);
        //可能性2:i 和 i+1位置一起转,两个位置结合的值小于27才有效
        if (i + 1 < str.length && (str[i] - '0') * 10 + str[i + 1] - '0' < 27) {
            ways += process(str, i + 2);
        }
        return ways;
    }
    
    public static void main(String[] args) {
        System.out.println(number("111111"));
    }
}

优化:修改为动态规划

递归函数里的可变参数只有一个,所以只需要一个一维表即可表示各种情况,然后再根据递归函数里的位置依赖关系填表。

public class ConvertToLetterString {
    public static int dpWay(String s) {
        if (s == null || s.length == 0) return 0;
        
        char[] str = s.toCharArray();
        int n = str.lenght;
        int[] dp = new int[n + 1];
        dp[n] = 1;
        //根据位置依赖,依赖于其后面的位置,所以从右往左填
        for (int i = n - 1; i >= 0; i--) {
            //在递归函数里做的事情就直接到dp表中取数据即可
            if (str[i] != '0') {
                int ways = dp[i + 1];
                if (i + 1 < str.length && (str[i] - '0') * 10 + str[i + 1] - '0' < 27) {
            		ways += dp[i + 2];
        		}
                dp[i] = ways;
            }
        }
        
        return dp[0];
    }
    
    public static void main(String[] args) {
        System.out.println(dpWay("111111"));
    }
}

你可能感兴趣的:(#,动态规划,动态规划,算法)