剑指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
}
posted @ 2021-12-28 10:38  西*风  阅读(35)  评论(0编辑  收藏  举报