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:) 拼接方式,整个流程直观又易读。

相关推荐
点云SLAM2 小时前
算法与数据结构之二叉树(Binary Tree)
数据结构·算法·二叉树·深度优先·广度优先·宽度优先
小龙报2 小时前
《算法通关指南:算法基础篇 --- 一维前缀和 — 1. 【模板】一维前缀和,2.最大子段和》
c语言·数据结构·c++·算法·职场和发展·创业创新·visual studio
程序员三藏2 小时前
一文了解UI自动化测试
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
敲敲了个代码2 小时前
11月3-5年Web前端开发面试需要达到的强度
前端·vue.js·学习·react.js·面试·职场和发展·web
bbq粉刷匠3 小时前
力扣--两数之和(Java)
java·leetcode
树在风中摇曳3 小时前
LeetCode 1658 | 将 x 减到 0 的最小操作数(C语言滑动窗口解法)
c语言·算法·leetcode
不夜牛仔3 小时前
算法笔记17 - 贪心算法介绍与思路 | 路灯摆放问题 | 活动安排问题 | 最低字典序拼接 | 金条分割问题 | 项目投资问题
笔记·算法·贪心算法
.柒宇.4 小时前
力扣hoT100之找到字符串中所有字母异位词(java版)
java·数据结构·算法·leetcode
松岛雾奈.2304 小时前
机器学习--KNN算法中的距离、范数、正则化
人工智能·算法·机器学习