【線性 dp】B005_LC_把數字翻譯成字符串(抽象)

一、Problem

給定一個數字,我們按照如下規則把它翻譯爲字符串:0 翻譯成 “a” ,1 翻譯成 “b”,……,11 翻譯成 “l”,……,25 翻譯成 “z”。一個數字可能有多個翻譯。請編程實現一個函數,用來計算一個數字有多少種不同的翻譯方法。

輸入: 12258
輸出: 5
解釋: 12258有5種不同的翻譯,分別是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"

提示:

0 <= num < 231

二、Solution

方法一:dp

  • 定義狀態
    • f[i]f[i] 表示前 ii 個數字可以翻譯成的字符串的方案數。
  • 思考初始化:
    • f[0...n)=1f[0...n) = 1,每一個單獨的數字必定是可以翻譯的。
  • 思考狀態轉移方程:難點在這,還是不能快速地找出方程…
    • 錯誤版本:如果 11a[i1]×10+a[i]2511 \leqslant a[i-1] × 10 + a[i] \leqslant 25,則有 f[i]=f[i]+f[i1]f[i] = f[i] + f[i-1];否則 f[i]=[i1]f[i] =[i-1]
  • 思考輸出f[n1]f[n-1]
class Solution {
    public int translateNum(int num) {
    	String s = num + "";
    	int n = s.length(), tot = 0, f[] = new int[n], a[] = new int[n];
    	for (char c : s.toCharArray()) 
    		a[tot++] = c-'0';
    	Arrays.fill(f, 1);

    	for (int i = 1; i < n; i++) {
    		int x = a[i-1] * 10 + a[i];
    		if (11 <= x && x <= 25) f[i] = f[i] + f[i-1];
    		else                    f[i] = f[i-1];
    	}
    	return f[n-1];
    }
}
  • 定義狀態
    • f[i]f[i] 表示前 ii 個數字可以翻譯成的字符串的方案數。
  • 思考初始化:
    • f[0...n)=1f[0...n) = 1,每一個單獨的數字必定是可以翻譯的。
  • 思考狀態轉移方程:難點在這,還是不能快速地找出方程…
    • 如果 ii 位置前面的兩個位置可以翻譯成字符串,則有 f[i]=f[i1]+f[i2]f[i] = f[i-1] + f[i-2]
    • 如果 ii 位置前面的兩個位置不能翻譯成字符串,則有 f[i]=f[i1]f[i] = f[i-1]
  • 思考輸出f[n]f[n]

注意狀態表示是前 i 個,所以 dp 數組的大小要開到 n+1

class Solution {
    public int translateNum(int num) {
    	String s = num + "";
    	int n = s.length(), tot = 0, f[] = new int[n+1], a[] = new int[n];
    	for (char c : s.toCharArray()) 
    		a[tot++] = c-'0';

    	Arrays.fill(f, 1);
    	for (int i = 2; i <= n; i++) {
    		int x = a[i-2] * 10 + a[i-1];
    		if (x == 10 || 11 <= x && x <= 25) 
                    f[i] = f[i-1] + f[i-2];
    		else    f[i] = f[i-1];
    	}
    	return f[n];
    }
}

這裏由於爲了方便編碼,我將數字轉爲了字符串,還有將字符串轉化成了整形數組,以及將整個數組都初始化爲了 1,所以效率較低,其實大可不必:

  • 字符串轉數字可以優化
  • 因爲 dp 的第三個位置只和前兩個位置又連續,所以開始的時候只用初始化 f[0] 和 f[1] 爲 1

複雜度分析

  • 時間複雜度:O(n)O(n)
  • 空間複雜度:O(n)O(n)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章