【LeetCode每日一题】2020.6.9 面试题46. 把数字翻译成字符串

面试题46. 把数字翻译成字符串

给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。

示例:

输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"

分析:

动态规划:

​ 对数字的每一位,都有两种选择:走1步(翻译一个数字)或者走2步(翻译两个数字)。因此我们可以在草稿纸上画出一个树的结构。

​ 仔细分析上图,我们可以看出,有许多重复计算的地方。

​ 如果在递归算法中反复求解同堂的子问题,我们就把这种性质称作重叠子问题。这是适合用动态规划方法求解的最优化问题应该具备的性质。

​ 因此我们就可以想到利用动态规划来求解问题。

滚动数组:

​ 动态规划的空间复杂度一般为O(n),实际上对于很多问题都有提升的空间。例如本题:我们不需要存储所有下标为i的数字翻译方式。只需要得到i为最后一位的结果。在此过程中,只需要不断更新i-2i-1位置上的结果就满足要求。这就是利用滚动数组思想来降低动态规划的时间复杂度。

代码:

package main

import (
	"fmt"
	"strconv"
)

// 直接递归
func translateNum1(num int) int {
	str := strconv.Itoa(num)
	var dfs func(str string, index int) int
	dfs = func(str string, index int) int {
		if index >= len(str) - 1 {
			return 1
		}
		temp := int(str[index] - '0') * 10 + int(str[index + 1] - '0')
		if temp >= 10 && temp <= 25 {
			return dfs(str, index + 1) + dfs(str, index + 2)
		} else {
			return dfs(str, index + 1)
		}
	}
	return dfs(str, 0)
}

// 递归加备忘
func translateNum2(num int) int {
	str := strconv.Itoa(num)
	memo := make([]int, len(str))
	var dfs func(str string, index int) int
	dfs = func(str string, index int) int {
		if index >= len(str) - 1 {
			return 1
		}
		if memo[index] != 0 {
			return memo[index]
		}
		temp := int(str[index] - '0') * 10 + int(str[index + 1] - '0')
		if temp >= 10 && temp <= 25 {
			memo[index] = dfs(str, index + 1) + dfs(str, index + 2)
		} else {
			memo[index] = dfs(str, index + 1)
		}
		return memo[index]
	}
	return dfs(str, 0)
}

// 自底向上
func translateNum3(num int) int {
	str := strconv.Itoa(num)
	n := len(str)
	// dp[i]保存前i个数有多少中翻译方式
	dp := make([]int, n + 1)  // 多存储一位,以方便理解
	dp[0] = 1
	dp[1] = 1
	for i := 2; i < n + 1; i++ {
		temp := int(str[i - 2] - '0') * 10 + int(str[i - 1] - '0')
		if temp >= 10 && temp <= 25 {
			dp[i] = dp[i - 2] + dp[i - 1]
		} else {
			dp[i] = dp[i - 1]
		}
	}
	return dp[n]
}

// 利用滚动数组压缩空间复杂度
func translateNum4(num int) int {
	str := strconv.Itoa(num)
	n := len(str)
	prev := 1
	cur := 1
	for i := 2; i < n + 1; i++ {
		temp := int(str[i - 2] - '0') * 10 + int(str[i - 1] - '0')
		if temp >= 10 && temp <= 25 {
			tmp := cur
			cur = prev + cur
			prev = tmp
		} else {
			prev = cur
		}
	}
	return cur
}
posted @ 2020-06-09 22:38  macguz  阅读(175)  评论(0编辑  收藏  举报