[題解]劍指 Offer 46. 把數字翻譯成字串 (C++)
阿新 • • 發佈:2021-08-20
題目
給定一個數字,我們按照如下規則把它翻譯為字串:0 翻譯成 “a” ,1 翻譯成 “b”,……,11 翻譯成 “l”,……,25 翻譯成 “z”。一個數字可能有多個翻譯。請程式設計實現一個函式,用來計算一個數字有多少種不同的翻譯方法。
示例 1:
輸入: 12258
輸出: 5
解釋: 12258有5種不同的翻譯,分別是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
提示:
\(0 <= num < 2^{31}\)
來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。
思路
這題看到的第一反應就是用動態規劃了,先把數字轉換成字串來考慮會方便一點,但是假設我們用dp[i]來表示前i個數字翻譯方法數,怎麼更新dp陣列呢?其實可以把結尾處的數字數也作為一個資訊,用一個二維陣列,dp[0][i]表示前i個數字,最後一個數字單獨翻譯的翻譯數;dp[1][i]表示前i個數字,最後兩個數字一起翻譯的翻譯數。dp[0][i]可以從dp[0][i-1]和dp[1][i-1]轉移過來,因為最後一個數字無所謂是什麼都可以翻譯;dp[1][i]就只能從dp[0][i-1]轉移過來,而且s[i-1]和s[i]組成的數字必須在10~25這個範圍內。
這樣,我們就能得到轉移方程了:
時間複雜度和空間複雜度都是O(n)。
程式碼
class Solution {
public:
int translateNum(int num) {
string s = to_string(num);
int n = s.size();
vector<vector<int>> dp(2, vector<int>(n));
dp[0][0] = 1;
dp[1][0] = 0;
for(int i = 1; i < n; ++i)
{
dp[0][i] = dp[0][i - 1] + dp[1][i - 1];
if(s[i - 1] == '1')
{
dp[1][i] = dp[0][i - 1];
}
else if(s[i - 1] == '2')
{
if(s[i] > '5')
{
dp[1][i] = 0;
}
else{
dp[1][i] = dp[0][i - 1];
}
}
else
{
dp[1][i] = 0;
}
}
return dp[0].back() + dp[1].back();
}
};
改進
仔細考慮更新dp陣列的過程,會發現在更新dp陣列在位置i的資訊時,只會用到最近一次更新後的dp[0][i - 1]和dp[1][i - 1],那麼可以只用兩個數dp1和dp2來更新,空間複雜度降低到O(1)。
程式碼
class Solution {
public:
int translateNum(int num) {
string s = to_string(num);
int n = s.size();
int dp1 = 1, dp2 = 0;
for(int i = 1; i < n; ++i)
{
int tmp1 = dp1;
dp1 = dp1 + dp2;
if(s[i - 1] == '1')
{
dp2 = tmp1;
}
else if(s[i - 1] == '2')
{
if(s[i] > '5')
{
dp2 = 0;
}
else{
dp2 = tmp1;
}
}
else
{
dp2 = 0;
}
}
return dp1 + dp2;
}
};