剑指offer-把数字翻译成字符串(dp)
给定一个数字,我们按照如下规则把它翻译为字符串: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
}