leetcode刷題(83)——面試題46. 把數字翻譯成字符串

對於題目的理解,其實也不難,我們並沒有必要把數字真的轉換成它要求的字母,只要得出有多少種分割方法就行了。

這種分割的問題也叫“隔板問題”——在數字之間的縫隙裏插入隔板,看有多少種分法,是一類組合問題。這裏由於受到26個字母的限制,只需要考慮分割之後,每兩個“隔間”內有兩個數字就可以了。也就是說,我們只需要考慮當前數字與它後面的數字的組合是不是在[10,25]內即可,這裏之所以是邊界是10,因爲會出現01,02這種,這種不是有效的2位數,不能轉化爲對應的字母

這麼想的話,實際上該問題已經有點像經典的“爬樓梯”問題了:一次上一階或者兩階,總共有多少種走法。於是自然想到了用動態規劃的解法,關鍵性的問題也就出現了:遞推公式是什麼?

首先我們一定能想到不復雜的情況:

只有一個數字時,不用切割,只有一種對映,dp[0] = 1;
dp[1]的值是多少實際上取決於字符串str[1]和str[0]構成的數字是不是處於[0,25]區間內——是,則dp[1] = 2;否則dp[1] = 1.
這兩條是最容易想到的,不過也確實爲後面的條件判斷打下基礎了。接下來是數學中的歸納法,通俗說是找規律。以題目中的輸入示例12258來看,dp[0] = 1, dp[1] = 2

dp[2] = 3((1,22), (12,2), (1,2,2))
dp[3] = 5 ((12,25), (1,2,25), (1,22,5), (12,2,5),(1,2,2,5))
dp[4]還是5,原因是str[4] = 8與str[3] = 5組合起來大於25,不能對映到一個字符,5和8之間必須切開,所以加上的這個數字8並不影響分割方式。
好了,上面的例子寫完,如果還沒找到規律可以接着往後寫。對於dp問題敏感的選手應該已經想到需要用上dp[i], dp[i-1]這些元素來總結遞推了:

2 <= i < len(str)
if str[i]和str[i-1]構成的數字 < 26:
    dp[i] = dp[i-1] + dp[i-2]   #等於前兩項之和
else:
    dp[i] = dp[i-1]             #不受影響直接等於前一項

代碼

public class Solution46m {
    public int translateNum(int num) {
        String res = String.valueOf(num);
        int[] dp = new int[res.length()];
        if (res.length() < 2) {
            return res.length();
        }
        dp[0] = 1;
        int firstSum = Integer.valueOf(res.substring(0, 2));
        dp[1] = firstSum >= 10 && firstSum <= 25 ? 2 : 1;
        for (int i = 2; i < res.length(); i++) {
            int sum = Integer.valueOf(res.substring(i - 1, i + 1));
            if (sum >= 10 && sum <= 25) {
                dp[i] = dp[i - 1] + dp[i - 2];
            } else {
                dp[i] = dp[i - 1];
            }
        }
        return dp[res.length()-1];
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章