算法 : 把数字翻译成字符串

牛客网

题目

复制代码
 有一种将字母编码成数字的方式:'a'->1, 'b->2', ... , 'z->26'。
现在给一串数字,返回有多少种可能的译码结果

数据范围:字符串长度满足 0<n≤900<n≤90
进阶:空间复杂度 O(n)O(n),时间复杂度 O(n)O(n) 

解析

这是一个经典的 动态规划(Dynamic Programming) 问题,通常被称为 "Decode Ways" 问题。


🔍 问题描述

给定一个仅包含数字的字符串,返回它可能解码成多少种字母组合。

编码规则:

  • 'a'1
  • 'b'2
  • ...
  • 'z'26

注意:0 不能单独作为一个字符,也不能作为开头。例如 "0""06" 都是非法的编码。


✅ 动态规划思路

定义 dp[i] 表示前 i 个字符的解码方式总数:

状态转移方程:

  1. 如果 s[i - 1] != '0',说明最后一个字符可以单独译码,所以:

    java 复制代码
    dp[i] += dp[i - 1]
  2. 如果前两个字符组成的数字在 10 ~ 26 范围内,则这两个字符可以一起译码:

    java 复制代码
    if (prevTwoDigits >= 10 && prevTwoDigits <= 26)
        dp[i] += dp[i - 2]

初始条件:

  • dp[0] = 1:空字符串有一种解法(即什么都不译)
  • dp[1] = 1 如果第一个字符不是 '0',否则为 0

✅ Java 实现

java 复制代码
public class Solution {
    public int numDecodings(String s) {
        if (s == null || s.length() == 0 || s.charAt(0) == '0') return 0;

        int n = s.length();
        int[] dp = new int[n + 1];
        dp[0] = 1;
        dp[1] = 1;

        for (int i = 2; i <= n; i++) {
            // 单个字符
            if (s.charAt(i - 1) != '0') {
                dp[i] += dp[i - 1];
            }

            // 两个字符
            int twoDigit = Integer.parseInt(s.substring(i - 2, i));
            if (twoDigit >= 10 && twoDigit <= 26) {
                dp[i] += dp[i - 2];
            }
        }

        return dp[n];
    }
}

✅ 时间与空间复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)(可优化至 O(1),只使用两个变量记录前两个状态)

✅ 空间优化版(滚动数组)

java 复制代码
public class Solution {
    public int numDecodings(String s) {
        if (s == null || s.length() == 0 || s.charAt(0) == '0') return 0;

        int prev2 = 1; // dp[i-2]
        int prev1 = 1; // dp[i-1]

        for (int i = 2; i <= s.length(); i++) {
            int curr = 0;
            if (s.charAt(i - 1) != '0') {
                curr += prev1;
            }

            int twoDigit = Integer.parseInt(s.substring(i - 2, i));
            if (twoDigit >= 10 && twoDigit <= 26) {
                curr += prev2;
            }

            prev2 = prev1;
            prev1 = curr;
        }

        return prev1;
    }
}

✅ 示例

输入:

java 复制代码
"12"

输出:

复制代码
2

解释:它可以被译码为 "AB" (1+2) 或 "L" (12)


🧠 小贴士

  • 处理边界情况要特别小心,比如以 '0' 开头的字符串。
  • 可以用 substring 提取子串,也可以用字符运算来提高效率。

如果你还想了解如何打印所有可能的译码结果,或者支持非 ASCII 字符等变体场景,也可以告诉我,我可以继续扩展。

相关推荐
SmartBrain1 分钟前
AI算法工程师面试:大模型和智能体知识(含答案)
人工智能·算法·语言模型·架构·aigc
孞㐑¥5 分钟前
算法—哈希表
开发语言·c++·经验分享·笔记·算法
近津薪荼20 分钟前
递归专题(2)——合并链表
c++·学习·算法·链表
Asher阿舍技术站21 分钟前
【数字通信理论系列】四、载波相位同步
算法·载波同步
-Try hard-25 分钟前
队列 | 二叉树
算法
Sagittarius_A*27 分钟前
灰度变换与阈值化:从像素映射到图像二值化的核心操作【计算机视觉】
图像处理·人工智能·opencv·算法·计算机视觉·图像阈值·灰度变换
Nie_Xun36 分钟前
卡尔曼滤波(EKF/IEKF)与非线性优化(高斯-牛顿法)的统一关系
算法
仰泳的熊猫1 小时前
题目1433:蓝桥杯2013年第四届真题-危险系数
数据结构·c++·算法·蓝桥杯·深度优先·图论
平哥努力学习ing1 小时前
补充 part 1——防御性编程
算法
wbs_scy1 小时前
C++:智能指针完全指南(原理、用法与避坑实战,从 RAII 到循环引用)
开发语言·c++·算法