Loading

数字字符串转换为字母组合的种数

数字字符串转换为字母组合的种数

题目:数字字符转化为字母组合的种数

《程序员代码面试指南》第71题 P238 难度:尉★★☆☆

这题不算很难,很快想出来,一个for循环了事,不过有些难理解。

我的思路是,假设数字字符串为“XXX...XXX”,那么“XXX...XXX”转换为字母组合的总数(记为p(N)),取决于倒数第一和第二个X

  • 如果倒数第一和第二个X能组合成1~26的二位数且倒数第二个X不为0,并且倒数第一个X不为0,那么p(N)=p(N-1)+p(N-2)
  • 如果倒数第一和第二个X能组合成1~26的二位数且倒数第二个X不为0,但倒数第一个X为0,那么p(N)=p(N-2)
  • 如果倒数第一和第二个X不能组合成1~26的二位数或倒数第二个X为0,但倒数第一个X不为0,那么p(N)=p(N-1)
  • 剩下的情况就是倒数第一和第二个X都为0,或者倒数第一和第二个X不能组合成1~26的二位数且倒数第一个X为0,那么p(N)=0

以上概括就是:

  • 倒数第二个X不为0能和倒数第一个X组合成1~26的二位数,p(N)+=p(N-2)
  • 倒数第一个X不为0p(N)+=p(N-1)

N换成i,使其具有一般性。按照这种思想从左向右逐个遍历,就能得出最终的结果。

我的代码如下:

public int counts(char[] num) {
    if(num == null || num.length == 0 || num[0] == '0')
        return 0;
    int last2 = 1, last1 = 1;
    int sum = 0, tmp = 0;
    for(int i=1; i<num.length; i++) {
        sum = 0;
        tmp = (num[i-1]-'0') * 10 + (num[i]-'0');
        if(num[i-1] != '0' && tmp <= 26)
            sum += last2;
        if(num[i] != '0')
            sum += last1;
        last2 = last1;
        last1 = sum;
    }
    return sum;
}

其中last2的初始值要设对为1而不为0),可以通过长度为2的字符串来验证。

至于书上的思路(从暴力递归到优化),和我大致一样,只不过书上是从右向左遍历,而我是从左向右遍历。具体可以参照书P238-240,这里不再赘述。(我感觉我的思路比书上的好理解(⊙o⊙)…)

书P240还提到,本题不能像斐波那契数列那题优化成矩阵乘法的,因为斐波那契数列是严格的f(i)=f(i-1)+f(i-2)。而本题的表达式是有状态转移的,如上所述,p(i)的值取决于左边两个数字,不是严格的p(i)=p(i-1)+p(i-2)。如果本题改成只由1和2字符组成,如“12121121212122”,那么此时一定有p(i)=p(i-1)+p(i-2),就可以使用矩阵乘法了。总之,可以使用矩阵乘法的前提递归表达式不会发生转移

最后贴出书上的代码:

public int num2(String str) {
    if (str == null || str.equals("")) {
        return 0;
    }
    char[] chs = str.toCharArray();
    int cur = chs[chs.length - 1] == '0' ? 0 : 1;
    int next = 1;
    int tmp = 0;
    for (int i = chs.length - 2; i >= 0; i--) {
        if (chs[i] == '0') {
            next = cur;
            cur = 0;
        } else {
            tmp = cur;
            if ((chs[i] - '0') * 10 + chs[i + 1] - '0' < 27) {
                cur += next;
            }
            next = tmp;
        }
    }
    return cur;
}
posted @ 2022-03-26 12:02  幻梦翱翔  阅读(192)  评论(0)    收藏  举报