給定一個數字,我們按照如下規則把它翻譯爲字符串:0 翻譯成 “a” ,1 翻譯成 “b”,……,11 翻譯成 “l”,……,25 翻譯成 “z”。一個數字可能有多個翻譯。請編程實現一個函數,用來計算一個數字有多少種不同的翻譯方法。
示例 1:
輸入: 12258
輸出: 5
解釋: 12258有5種不同的翻譯,分別是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
提示:
0 <= num < 231
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof
分析:
動態規劃
dp[n-1]代表截止到下標爲n-1的字符,其方案數
對下標爲i的字符來說,其方案數其實取決於前面字符的方案數,是前面字符的狀態轉移,所以可以對當前字符和前一個字符討論,得到其狀態轉移方程
如果str[i]和str[i-1]可以組成一個字符,則dp[i]=dp[i-2]+dp[i-1]
如果str[i]和str[i-1]不能組成一個字符,則dp[i]=dp[i-1]
以12258爲例
字符: 1 2 2 5 8
方案: 1 2 3 5 5
i=0方案:1種
1
i=1的方案:2種
1 2
12
i的方案:(取決於i和i-1能否組成新字符串)
假設i=2,其方案如下:
1 22 =====> i-2的方案+後面加新組成的字符串
1 2 2 =====> i-1的方案+後面str[i]字符
12 2
假設i=3,其方案如下:
1 2 25 =====> i-2的方案+後面加新組成的字符串
12 25
1 22 5 =====> i-1的方案+後面str[i]字符
1 2 2 5
12 2 5
假設i=4,str[i]和str[i-1]值爲58,不能組成新的字符
所有其方案數等於i-1的方案數量
1 2 25 8
12 25 8
1 22 5 8
1 2 2 5 8
12 2 5 8
就是i-1的所有方案,後面加一個字符8,其總的方案數量還是沒有變的
當前方法是時間複雜度爲O(N),如果用額外的dp數組記錄,則其空間複雜度爲O(N),但是每次計算只依賴於前面兩項,可以採取滾動計數的形式,這樣空間複雜度可以簡化到O(1)
1.dp數組記錄
時間複雜度:O(N)
空間複雜度:O(N)
func translateNum(num int) int {
str := strconv.Itoa(num)
n := len(str)
var dp [105]int
dp[0]=1
if n==1{
return dp[0]
}
temp,_:=strconv.ParseInt(str[0:2],10,64)
if temp>=10&&temp<=25{
dp[1]=2
}else {
dp[1]=1
}
for i := 2; i < n; i++ {
temp, _ := strconv.ParseInt(str[i-1:i+1], 10, 64)
if temp >= 10 && temp <= 25 {
dp[i] = dp[i-1] + dp[i-2]
} else {
dp[i] = dp[i-1]
}
}
return dp[n-1]
}
2.滾動計數
時間複雜度:O(N)
空間複雜度:O(1)
func translateNum(num int) int {
str := strconv.Itoa(num)
n := len(str)
var k1,k2,k3 int
k1=1
if n==1{
return k1
}
temp,_:=strconv.ParseInt(str[0:2],10,64)
if temp>=10&&temp<=25{
k2=2
}else {
k2=1
}
if n==2{
return k2
}
for i := 2; i < n; i++ {
temp, _ := strconv.ParseInt(str[i-1:i+1], 10, 64)
if temp >= 10 && temp <= 25 {
k3=k2+k1
} else {
k3=k2
}
k1=k2
k2=k3
}
return k3
}