程序员面试金典 - 面试题 16.08. 整数的英语表示

题目难度: 困难

原题链接

今天继续更新程序员面试金典系列, 大家在公众号 算法精选 里回复 面试金典 就能看到该系列当前连载的所有文章了, 记得关注哦~

题目描述

给定一个整数,打印该整数的英文描述。

示例 1:

  • 输入: 123
  • 输出: “One Hundred Twenty Three”

示例 2:

  • 输入: 12345
  • 输出: “Twelve Thousand Three Hundred Forty Five”

示例 3:

  • 输入: 1234567
  • 输出: “One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven”

示例 4:

  • 输入: 1234567891
  • 输出: “One Billion Two Hundred Thirty Four Million Five Hundred Sixty Seven Thousand Eight Hundred Ninety One”

题目思考

  1. 需要考虑哪些情况?

解决方案

思路
  • 观察题目, 我们可以发现, 数字的英文表示有这样的规律: 从个位开始, 每三个数字为一组, 可以使用相同的方式转换; 然后后面跟上当前的单位, 如 Thousand/Million
  • 所以我们可以模拟这个过程, 从右向左遍历, 每 3 位数字一组, 将其转换成英文表示并添加单位的过程提取出来
  • 具体细节方面, 我们需要考虑以下几种情况:
    1. 0 : 只有单独 0 才需要输出 Zero; 其他情况下遇到 0 都不输出 Zero
    2. 个位: 最简单的情况, 每个数字可以映射为一个单独的单词
    3. 十位: 需要额外构建 10~19 以及 20,30,…,90 与对应英文单词的映射关系
    4. 百位: 非 0 时, 需要额外添加 Hundred
    5. 千位/百万位/十亿位: 非 0 时, 需要额外添加 Thousand/Million/Billion
  • 实现方面, 我们可以:
    1. 维护一个统一的数字到单词的映射字典, 包含 0~9, 10~19 以及 20,30,…,90 与对应英文单词的映射关系
    2. 维护当前位数下标, 用于判断是否构成 3 位一组
    3. 维护当前的千位单位下标以及对应的单词
    4. 将转换 3 位一组数字到对应英文表示并添加单位的过程提取成函数, 里面单独处理百十个位
    5. 结果先输出到字符串数组, 最终再统一用空格隔开, 避免额外的空格处理
    6. 特别注意循环结束时累积的数字可能不足 3 位, 它们也需要转成字符串
  • 下面代码就对应了上面的整个过程, 且每一步有详细的注释, 方便大家理解
复杂度
  • 时间复杂度 O(1): 只遍历了常数长度的数字
  • 空间复杂度 O(1): 只使用了几个常数空间的变量
代码
class Solution:
    def numberToWords(self, num: int) -> str:
        # maps存储数字和对应单词的映射关系, 注意10~19以及20~90的映射
        maps = {0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four", 5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine", 10: "Ten", 11: "Eleven", 12: "Twelve", 13: "Thirteen", 14: "Fourteen", 15: "Fifteen", 16: "Sixteen", 17: "Seventeen", 18: "Eighteen", 19: "Nineteen", 20: "Twenty", 30: "Thirty", 40: "Forty", 50: "Fifty", 60: "Sixty", 70: "Seventy", 80: "Eighty", 90: "Ninety"}
        # units存储千位单位
        units = [[], ["Thousand"], ["Million"], ["Billion"]]
        if num == 0:
            # 单独0, 直接返回Zero, 其他情况下都不会输出Zero
            return maps[0]

        def convertToList(num, ui):
            # 独立方法, 将一组三位数字转成对应的英文表示, 并加上相应千位单位
            if num == 0:
                # 注意如果num是0的话直接返回空, 不管ui是什么, 否则1000000会被转换成One Million Thousand
                return []
            # 先转成[百,十,个]数组
            nums = [num // 100 % 10, num // 10 % 10, num % 10]
            res = []
            for i, x in enumerate(nums):
                if x == 0:
                    # 遇到0, 直接跳过
                    continue
                if i == 1:
                    # 当前是十位
                    if x == 1:
                        # 10~19, 合并当前位和下一位的数字, 使用Ten到Nineteen, 退出循环
                        res.append(maps[x * 10 + nums[i + 1]])
                        break
                    else:
                        # 20+, 使用Twenty到Ninety
                        res.append(maps[x * 10])
                else:
                    # 百位和个位都直接使用单个单词
                    res.append(maps[x])
                if i == 0:
                    # 百位, 需要额外加上Hundred
                    res.append("Hundred")
            # 注意额外加上当前的千位单位
            return res + units[ui]

        # i是当前的位数下标
        i = 0
        # ui是当前的千位单位下标, 第一组是空, 第二组是Thousand, 第三组是Million, 依此类推
        ui = 0
        # cur保存当前处理的数字
        cur = 0
        res = []
        while num:
            # 将当前数字累加到cur
            cur += (num % 10) * (10 ** (i % 3))
            num //= 10
            i += 1
            if i % 3 == 0:
                # 此时达到分界点, 将当前的三位数字作为一组, 转换成字符串
                res = convertToList(cur, ui) + res
                # 注意更新千位单位下标和cur
                ui += 1
                cur = 0
        # 注意循环结束时cur有可能不是0, 但是没达到3位, 也需要转成字符串
        res = convertToList(cur, ui) + res
        # 将字符串数组中间加上空格, 即为最终结果
        return " ".join(res)

大家可以在下面这些地方找到我~😊

我的 GitHub

我的 Leetcode

我的 CSDN

我的知乎专栏

我的头条号

我的牛客网博客

我的公众号: 算法精选, 欢迎大家扫码关注~😊

算法精选 - 微信扫一扫关注我

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值