LeetCode 423 - 从英文中重建数字


文章目录

摘要

这道题《LeetCode 423. 从英文中重建数字(Reconstruct Original Digits from English)》挺有意思。

它不是那种常规的数值运算题,而更像是一个"单词拼图"挑战。

题目把一些英文数字单词(zero, one, two, ..., nine)打乱顺序混合在一起,我们要根据这些字母重新推算出原始的数字序列。

看起来有点像解谜游戏,其实考的就是"字符串计数 + 特征提取"的能力。

这种题型在自然语言处理、OCR后文本修复、甚至语音识别转写矫正中都有类似的逻辑。

描述

给定一个字符串 s,其中包含被打乱顺序的英文单词表示的数字(zeronine)。

要求我们按升序返回这些数字的字符串表示。

例如:

txt 复制代码
输入: s = "owoztneoer"
输出: "012"
解释: "zero" + "one" + "two" 的字母混合在一起。

再比如:

txt 复制代码
输入: s = "fviefuro"
输出: "45"
解释: 包含 "four" + "five"

题目还保证输入一定能组成合法的数字单词集合,不用考虑无法解析的情况。

题解答案

解决这道题的关键在于:每个数字单词都有独特的字母特征

比如:

  • "z" 只出现在 "zero" 中,所以每出现一个 "z",就一定有一个 "0"。
  • "w" 只出现在 "two" 中。
  • "u" 只出现在 "four" 中。
  • "x" 只出现在 "six" 中。
  • "g" 只出现在 "eight" 中。

这些独特字符让我们可以先识别出部分数字。

然后再根据这些数字中已用掉的字母,反推出剩下的数字。

举个例子:

  • "h" 出现在 "three" 和 "eight" 中,但如果先算出 "eight",剩下的 "h" 只能来自 "three"。
  • "f" 出现在 "four" 和 "five" 中,去掉 "four" 后剩下的 "f" 就属于 "five"。

所以整个过程其实是一个按特征顺序剥洋葱的过程。

题解代码分析

下面是完整可运行的 Swift 代码:

swift 复制代码
import Foundation

class Solution {
    func originalDigits(_ s: String) -> String {
        // 1. 统计每个字母的出现次数
        var count = [Character: Int]()
        for c in s {
            count[c, default: 0] += 1
        }

        // 2. 用数组存每个数字出现的次数
        var res = [Int](repeating: 0, count: 10)

        // 3. 按独特字符特征判断数字
        res[0] = count["z"] ?? 0  // zero
        res[2] = count["w"] ?? 0  // two
        res[4] = count["u"] ?? 0  // four
        res[6] = count["x"] ?? 0  // six
        res[8] = count["g"] ?? 0  // eight

        // 4. 推导剩余数字
        res[3] = (count["h"] ?? 0) - res[8] // three
        res[5] = (count["f"] ?? 0) - res[4] // five
        res[7] = (count["s"] ?? 0) - res[6] // seven
        res[1] = (count["o"] ?? 0) - res[0] - res[2] - res[4] // one
        res[9] = (count["i"] ?? 0) - res[5] - res[6] - res[8] // nine

        // 5. 组合结果
        var ans = ""
        for i in 0..<10 {
            ans += String(repeating: "\(i)", count: res[i])
        }
        return ans
    }
}

// Demo 测试
let s = Solution()
print("测试1:", s.originalDigits("owoztneoer"))  // 输出 "012"
print("测试2:", s.originalDigits("fviefuro"))    // 输出 "45"

代码解析

  1. 计数字母:用一个字典统计每个字母出现的次数。

  2. 识别独特字符

    • "z" 对应 0
    • "w" 对应 2
    • "u" 对应 4
    • "x" 对应 6
    • "g" 对应 8
  3. 再推剩余的

    因为这些数字会"消耗"掉某些字母,所以我们减去它们的数量,再得出其他数字的数量。

  4. 结果拼接:按从小到大的顺序拼接数字字符串。

这段代码的逻辑非常清晰,也贴近实际字符串统计的套路,完全可以迁移到类似文本频率计算的业务场景中。

示例测试及结果

示例 1:

txt 复制代码
输入: s = "owoztneoer"
输出: "012"

解释:包含 "zero", "one", "two",重新排列后输出 012。

示例 2:

txt 复制代码
输入: s = "fviefuro"
输出: "45"

解释:包含 "five", "four",升序排列后输出 45。

执行结果:

txt 复制代码
测试1: 012
测试2: 45

代码输出与预期一致。

时间复杂度

O(N)

每个字符只统计和访问一次,后续推导都是常数操作,因此整体线性时间复杂度。

即使字符串长度达到 10⁵ 级别,也完全没问题。

空间复杂度

O(1)

因为英文字母表大小固定,数字种类也固定,所以空间使用不随输入增长。

严格来说我们用了一些字典和固定数组,但总体为常数级。

总结

这道题的核心是"找到独特特征字符"这一思路,非常有启发性。

它看似是纯算法题,其实背后逻辑和自然语言特征提取符号消歧模式识别等领域非常接近。

在实际开发中,如果遇到:

  • OCR 识别出的混乱文本;
  • 用户输入中带有模糊词;
  • 或日志关键词识别中多个重叠的特征词;

都可以借鉴类似的"频率减法"思路:

先确定独特特征,再逐步剥离剩余部分,最终恢复完整结构。

Swift 在处理这类计数逻辑时的写法也非常简洁------利用字典的默认值和 String(repeating:count:) 拼接方式,整个流程直观又易读。

相关推荐
gihigo199833 分钟前
matlab 基于瑞利衰落信道的误码率分析
算法
foxsen_xia1 小时前
go(基础06)——结构体取代类
开发语言·算法·golang
foxsen_xia1 小时前
go(基础08)——多态
算法·golang
leoufung1 小时前
用三色 DFS 拿下 Course Schedule(LeetCode 207)
算法·leetcode·深度优先
im_AMBER2 小时前
算法笔记 18 二分查找
数据结构·笔记·学习·算法
C雨后彩虹2 小时前
机器人活动区域
java·数据结构·算法·华为·面试
MarkHD3 小时前
车辆TBOX科普 第53次 三位一体智能车辆监控:电子围栏算法、驾驶行为分析与故障诊断逻辑深度解析
算法
苏小瀚3 小时前
[算法]---路径问题
数据结构·算法·leetcode
月明长歌3 小时前
【码道初阶】一道经典简单题:多数元素(LeetCode 169)|Boyer-Moore 投票算法详解
算法·leetcode·职场和发展
wadesir4 小时前
C语言模块化设计入门指南(从零开始构建清晰可维护的C程序)
c语言·开发语言·算法