《程序员面试金典(第6版)》面试题 16.08. 整数的英语表示

news2024/7/4 4:49:14

题目描述

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

示例 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”

提示:

  • 0 <= num <= 2^31 - 1

解题思路与代码

  • 不知道大家怎么看这道题,但是我觉得,这道题算是一道好题。不过这道题对英语不好的朋友可能就不那么友好了。

  • 在中文里,我们习惯四位数分为一组,比如1,0000就是一万。1,0000,0000就是一亿。

  • 而英文呢,它们习惯是三位一组,它们没有万的概念。也没有亿的概念。转而是1,000这就是这就是一千(Thousand),而10000则是Ten Thousand(我们说是1万,而它们就是10千),1,000,000则就是Million(也就是百万)它们有百万的概念。再往后,它们没有亿的概念,但是有10亿的概念,也就是1,000,000,000 Billion

  • 英文里面,0到19里面每个数字对应的英文都不一样。分别是:Zero(零),One(一),Two(二),Three(三),Four(四),Five(五),Six(六),Seven(七),Eight(八),Nine(九),Ten(十),Eleven(十一),Twelve(十二),Thirteen(十三),Fourteen(十四),Fifteen(十五),Sixteen(十六),Seventeen(十七),Eighteen(十八),Nineteen(十九)

  • 紧接着,英语里面20,30,40…100的英文单词也都不一样,分别是:Twenty(二十),Thirty(三十),Forty(四十),Fifty(五十),Sixty(六十),Seventy(七十),Eighty(八十),Ninety(九十),Hundred(百)

  • 最后就是几个大单位表示了:Thousand(千),Million(百万),Billion(十亿)

  • 小于20的表示方法就是对应的单个英文数字,以20,30,…100这样的乘10整数就对应英语里面的20,30^100,那像 23 表示也就是 20 + 3 ,比如就是 Twenty Three ,123 就是 One Hundred Twenty Three 小于1000的大家可以自己类别。

  • 我们之间讲到英语是3位一组的,所以每三位,就会加一个单位,这个单位是加在前3位之后,后三位之前的。比如 1234 就是 One Thousand Two Hundred Thirty Four ,1234567 就是 One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven,1234567890 就是 One Billion Two Hundred Thirty Million Five Hundred Sixty Seven Thousand Eight Hundred Ninety。

  • 聪明的大家,一定懂了,我像表达的意思了吧。

这道题,也算是给大家补充中英区别的小知识了。紧接着,其实就是转换问题。我认为转换问题不是难事。我们只需要将数字与英文直接建立起联系就好了。

那如何建立起联系呢?我这边有两种,一种就是哈希映射,另一种呢?其实就是vector数组。

而这道题的解决方法也有两种,一种是迭代,一种是递归。两种都可以。

那么我接下来,我就一点一点的来展现给大家。

方法一:哈希映射 + switch结构(迭代方案)

这种方法是我第一种想出来的方法,我认为这种方法实在是十分的简易好懂,并且逻辑关系清晰。不过缺点就是有点无脑,复杂度较高。

接下来,我来给大家讲讲我这道题的解题思路:我首先,是将除了大单位外每一个可能出现的英语单词,分为3组,分别用哈希映射的方式,放入3个unordered_map<int,string>中。
然后命名4个int,billion,million,thousand,remainder分别对应着3个大单位,与小于最小的大单位可能出现的3位数。比如123000,thousand = 123。

之后只需要再创建一个string 去存储最后的结果,在用if判断,去依次判断billion,million,thousand的值是否大于0,如果大于0,就调用一个函数去生成结果,最后依次加上对应的结果就好。

函数里面写的就是,如何处理进来的3位数的逻辑。如果是0-9我们怎么样,10-19我们怎么样,等等。

具体的实现,请看代码:

class Solution {
public:
    string numberToWords(int num) {
        if (num == 0) return "Zero";
        string res = "";

        int billion = num / 1000000000;
        int million = (num % 1000000000) / 1000000;
        int thousand = (num % 1000000) / 1000;
        int remainder = num % 1000;

        if (billion > 0) res += getHundreds(billion) + " Billion";
        if (million > 0) {
            if (!res.empty()) res += " ";
            res += getHundreds(million) + " Million";
        }
        if (thousand > 0) {
            if (!res.empty()) res += " ";
            res += getHundreds(thousand) + " Thousand";
        }
        if (remainder > 0) {
            if (!res.empty()) res += " ";
            res += getHundreds(remainder);
        }

        return res;
    }

    string getHundreds(int num){
        string strNum = to_string(num);
        int size = strNum.size();

        unordered_map<int,string> map{
                    {0,"Zero"},{1,"One"},{2,"Two"},{3,"Three"},
                    {4,"Four"},{5,"Five"},{6,"Six"},{7,"Seven"},
                    {8,"Eight"},{9,"Nine"}
        };
        unordered_map<int,string> map1{
                    {10,"Ten"},{11,"Eleven"},{12,"Twelve"},{13,"Thirteen"},
                    {14,"Fourteen"},{15,"Fifteen"},{16,"Sixteen"},{17,"Seventeen"},
                    {18,"Eighteen"},{19,"Nineteen"}
        };
        unordered_map<int,string> map2{
                    {20,"Twenty"},{30,"Thirty"},{40,"Forty"},{50,"Fifty"},
                    {60,"Sixty"},{70,"Seventy"},{80,"Eighty"},{90,"Ninety"},
        };

        switch(size){
            case 1:
                return map[num];
            case 2:{
                if(num < 20){
                    return map1[num];
                }else if(num >=20 && num % 10 == 0){
                    return map2[num];
                }else{
                    int ones = num % 10;
                    string strOnes = map[ones];
                    int tensDigit = num - ones;
                    string strTD = map2[tensDigit];
                    strTD += " ";
                    strTD += strOnes;
                    return strTD;
                }
            }
            case 3:{
                string result = "";
                int hundreds_digit = num / 100;
                result += map[hundreds_digit];
                result += " Hundred";
                num %= 100;

                if(num < 20 && num > 9){
                    result += " ";
                    result += map1[num];
                    return result;
                }else if(num <= 9){
                    if(num == 0) return result;
                    result += " ";
                    result += map[num];
                    return result;
                }else{
                    int onesDigit = num % 10;
                    int tensDigit = num - onesDigit;
                    result += " ";
                    result += map2[tensDigit];
                    if(onesDigit == 0) return result;
                    result += " ";
                    result += map[onesDigit];
                    return result;
                }
            }
        }
        return "";
    }
};

复杂度分析

时间复杂度:

  • 时间复杂度是由两个主要部分组成的:numberToWords() 函数和 getHundreds() 函数。numberToWords() 函数的时间复杂度主要取决于 getHundreds() 函数调用的次数,最多为 4 次(分别是十亿、百万、千和余数)。getHundreds() 函数中的运算和查找操作的时间复杂度为 O(1)。因此,整个程序的时间复杂度可以表示为 O(1)。

空间复杂度:

  • 空间复杂度主要取决于两个因素:局部变量(包括整数和字符串)和哈希表。局部变量的空间复杂度为 O(1)。哈希表的空间复杂度取决于它们的大小,但是由于它们的大小是固定的,所以哈希表的空间复杂度也为 O(1)。综上,整个程序的空间复杂度可以表示为 O(1)。

在这里插入图片描述

方法二:方法一的优化升级,用vector代替unordered_map,用if_else代替switch(迭代方案)

这个做法,稍微比上个做法高明了些,具体在于,我们用4个vector去存储,每一个对应可能出现的英语代码,去替代上一回的哈希映射。

用for循环每次去除1000,去代替上一种解决方案里面的4个int变量。

写的那个函数,我们也不用switch语句了,直接改成if判断语句。具体的做法就是这样,代码的逻辑并没有变,还是依旧是迭代遍历。

class Solution {
public:
    vector<string> singles = {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"};
    vector<string> teens = {"Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"};
    vector<string> tens = {"", "Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"};
    vector<string> thousands = {"", "Thousand", "Million", "Billion"};
    string numberToWords(int num) {
        if(num == 0) return "Zero";
        string result = "";
        for(int i = 3,unit = 1000000000; i >= 0; --i,unit /= 1000){
            int curr = num / unit;
            if(curr != 0){
                num -= curr * unit;
                result += toEnglish(curr);
                result += thousands[i];
                result += " ";
            }
        }
        while(result.back() == ' ') result.pop_back();
        return result;
    }
    string toEnglish(int num){
        string res = "";
        int hundred = num / 100;
        num %= 100;
        if(hundred > 0){
            res +=  singles[hundred];
            res += " Hundred ";
        } 
        int ten = num / 10;
        if(ten >= 2){
            num %= 10;
            res += tens[ten];
            res += " ";
        }
        if(num > 0 && num <= 9 ){
            res += singles[num];
            res += " ";
        }else if(num >= 10){
            res += teens[num - 10];
            res += " ";
        }
        return res;
    }
};

在这里插入图片描述

复杂度分析

时间复杂度:

  • 时间复杂度是由两个主要部分组成的:numberToWords() 函数和 toEnglish() 函数。numberToWords() 函数中的循环固定运行 4 次(分别是十亿、百万、千和余数)。在每次循环中,会调用一次 toEnglish() 函数。toEnglish() 函数中的运算和查找操作的时间复杂度为 O(1)。因此,整个程序的时间复杂度可以表示为 O(1)。

空间复杂度:

  • 空间复杂度主要取决于两个因素:局部变量(包括整数和字符串)和向量。局部变量的空间复杂度为 O(1)。向量的空间复杂度取决于它们的大小,但是由于它们的大小是固定的,所以向量的空间复杂度也为 O(1)。综上,整个程序的空间复杂度可以表示为 O(1)。

方法三:方案二的变式,副函数用递归去处理

方法三的主函数的逻辑不变,变的其实就是副函数如何处理3位数转换成英文的逻辑。

我觉得这种方式,是三种方法里面最简单易懂的副函数处理方法。极具代码美感

具体的代码如下:

class Solution {
public:
    vector<string> singles = {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"};
    vector<string> teens = {"Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"};
    vector<string> tens = {"", "Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"};
    vector<string> thousands = {"", "Thousand", "Million", "Billion"};
    string numberToWords(int num) {
        if(num == 0) return "Zero";
        string result;
        for(int i = 3,unit = 1000000000; i >=0; --i, unit /= 1000){
            int curNum = num / unit;
            if(curNum != 0){
                num %= unit;
                toEnglish(result,curNum);
                result += thousands[i];
                result += " ";
            }
        }
        while(result.back() == ' ') result.pop_back();
        return result;
    }
    void toEnglish(string& str,int curNum){
        if(curNum == 0) return;
        if(curNum < 10){
            str += singles[curNum];
            str += " ";
        }else if(curNum < 20){
            str += teens[curNum - 10];
            str += " ";
        }else if(curNum < 100){
            int ten = curNum / 10;
            str += tens[ten];
            str += " ";
            toEnglish(str,curNum % 10);
        }else {
            int hundred = curNum / 100;
            str += singles[hundred];
            str += " Hundred ";
            toEnglish(str,curNum % 100);
        }
    }
};

在这里插入图片描述

复杂度分析

时间复杂度:

  • 时间复杂度主要取决于 numberToWords() 函数和 toEnglish() 函数。numberToWords() 函数中的循环固定运行 4 次(分别是十亿、百万、千和余数)。在每次循环中,会调用一次 toEnglish() 函数。toEnglish() 函数的时间复杂度主要取决于递归调用的深度,最大深度为 3。因此,整个程序的时间复杂度可以表示为 O(1)。

空间复杂度:

  • 空间复杂度主要取决于两个因素:局部变量(包括整数和字符串)和向量。局部变量的空间复杂度为 O(1)。向量的空间复杂度取决于它们的大小,但是由于它们的大小是固定的,所以向量的空间复杂度也为 O(1)。此外,toEnglish() 函数采用了引用参数,因此不会引入额外的空间开销。综上,整个程序的空间复杂度可以表示为 O(1)。

总结

这三种方法各有优缺点。方法一使用哈希表实现,查找速度快,但代码略显冗长。方法二和三使用向量实现,代码简洁,其中方法三还采用了递归方式,进一步简化了代码,使代码极具美感。

总的来说,这对于练习编程逻辑和数字处理是一个很好的实践。

最后的最后,如果你觉得我的这篇文章写的不错的话,请给我一个赞与收藏,关注我,我会继续给大家带来更多更优质的干货内容

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/479876.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kali 更换源(超详细,附国内优质镜像源地址)

1.进入管理员下的控制台。 2. 输入密码后点击“授权”。 3.在控制台内输入下面的内容。 vim /etc/apt/sources.list 4.敲击回车后会进入下面的页面。 5.来到这个页面后的第一部是按键盘上的“i”键&#xff0c;左下角出现“插入”后说明操作正确。 6.使用“#”将原本的源给注释…

武汉大学惯性导航课程合集【2021年秋】1.2 惯性器件的误差和标定

前提平台惯导NED与本地对齐&#xff0c;body系和navigation对齐。地表IMU感受到的是 朝天上的力【0&#xff0c;0&#xff0c;-9.8】和 赤道的【15deg/hr&#xff0c;0&#xff0c;0】或者北极 【0&#xff0c;0&#xff0c;-15deg/hr】或者【15cos纬度&#xff0c;0&#xff0…

「STM32入门」USART串口通信

通信 通信的目的&#xff1a;将一个设备的数据传送到另一个设备&#xff0c;扩展硬件系统 通信协议&#xff1a;制定通信的规则&#xff0c;通信双方按照协议规则进行数据收发 STM32常见的通信协议 本文将介绍USART 概念解释 TX、RX分别是Transmit和Receive的缩写&#xff0c…

一文把 JavaScript 中的 this 聊得明明白白

文章目录 1.this 是什么&#xff1f;2.this的指向2.1 全局上下文的 this 指向2.2 函数&#xff08;普通函数&#xff09;上下文中的 this 指向2.3 事件处理程序中的 this 指向2.4 以对象的方式调用时 this 的指向2.5 构造函数中的 this 指向2.6 在 类上下文中 this 的指向。2.7…

开源企业资源规划ERPNext的安装

往常节假日&#xff0c;都是呆在家里看别人堵&#xff0c;这回老苏也出门凑了个热闹&#xff0c;28号早上 7 点半出的门 2 点半往回走的 一天啥也没干&#xff0c;就开了 7 个小时的车去舅舅家蹭了顿饭。还别说&#xff0c;那个田园鸡味道是真不错。 车很久没开了&#xff0c;…

(详解)vue中实现 ‘换肤 / 主题切换’ 功能的三种方式

目录 一、背景 二、实现思路 方法1&#xff1a;定义全局的CSS变量 方法2&#xff1a;切换已定义好的css文件 方法3&#xff1a;切换顶级CSS类名 (需使用css处理器,如sass、less等) 一、背景 在我们开发中我们会遇到像是需要切换程序风格、主题切换啦这种应用场景。 二、实现…

JavaScript通过函数异常处理来输入圆的半径,输出圆的面积的代码

以下为实现通过函数异常处理来输入圆的半径&#xff0c;输出圆的面积的代码和运行截图 目录 前言 一、通过函数异常处理来输入圆的半径&#xff0c;输出圆的面积 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有选择&#xff0c;您可以…

【RPA开发】pymongo 使用教程

实际开发时抓取到的诸多数据如何保存是一个关键问题&#xff0c;MongoDB 相比传统关系型数据库&#xff08;比如mysql&#xff09;来说灵活度更高&#xff0c;爬虫时字段格式及数量很可能会随着需求或实际数据的变动而改变&#xff0c;因此 MongoDB 作为数据库来说最合适不过了…

2023年华中杯选题人数公布

2023年华中杯选题人数公布 经过一晚上代码的编写&#xff0c;论文的写作&#xff0c;C题完整版论文已经发布&#xff0c; 注&#xff1a;蓝色字体为说明备注解释字体&#xff0c;不能出现在大家的论文里。黑色字体为论文部分&#xff0c;大家可以根据红色字体的注记进行摘抄。…

【STM32】知识补充 分频技术深度解析: 原理、应用与实现方法

【STM32】知识补充 分频技术深度解析: 原理、应用与实现方法 概述分频概念分频原理技术器分频器触发器分频器模数计数器分频器 分频应用微控制器时钟分频通信系统中的频率合成数字电路设计中的计时与同步 分频实现方法硬件分频器软件分频器 案例总结 概述 分频 (Frequency Div…

c#笔记-创建一个项目

创建一个项目 创建控制台程序 在你安装完成Visual Studio后打开它&#xff0c;你会的到一个启动窗口 点击创建新项目&#xff0c;选择右上角c#的没有Framework的控制台应用。 项目名称&#xff0c;位置自己随意。 目标框架选择NET7.0。 项目创建完成后应该你的界面应该类似…

nvdec与vaapi与vdpau的关系

nvdec/vaapi/vdpau的关系 NVDEC&#xff1a;nvidia video decoder。 英伟达官网中有关video codec SDK的介绍&#xff0c;其中有头文件、开发API文档等。 Nvidia Video SDK中提供了NVDEC、NVENC&#xff0c;其中NVDEC以前也叫做NVCUVID&#xff08;不知道NVDEC的开发API中很…

【9.HTML入门知识-其他知识补充】

其他知识补充 1.使用Web字体和图标1.1 web fonts兼容性写法1.2 字体图标1.2.1 字体图标的使用 2.精灵图 CSS Sprite2.1 精灵图的使用 3.置鼠标指针&#xff08;光标&#xff09;样式cusor4.居中方案4.1 使用绝对定位元素居中 1.使用Web字体和图标 1.1 web fonts兼容性写法 1.2 …

软件开发团队的护网低成本应对方案

主题&#xff1a; 1、攻击方技术手段说明&#xff0c;结合攻击队手段重点关注的防御点介绍&#xff1b; 2、防守方&#xff08;软件开发团队&#xff09;的低成本应对思路&#xff1b;系统是如何被攻破的 攻防演练&#xff08;APT&#xff09;攻击路径 未知攻&#xff0c;焉知…

IGH EtherCAT主站应用层代码开发:控制驱动电机

1、安装IGH EtherCAT主站 Ubuntu18.04环境下安装igH EtherCAT Master 2、查询从站配置信息 连接从站通过网线连接主站与从站 启动主站打开终端,输入: sudo /etc/init.d/ethercat star 显示Starting EtherCAT master 1.5.2 done则说明成功。 查询从站列表终端输入: eth…

【C++】 list-map 链表与映射表的简单使用

目录 list 链表 定义链表&#xff0c;并在首、尾添加、删除元素 迭代器遍历链表 任意位置插入或删除 获取首尾节点中元素的值 使用增强的范围for循环进行遍历链表 其他常见的函数 map 映射表 定义map 添加 使用函数插入元素 迭代器遍历map 修改 删除 使用增强的范…

PMP项目管理-[第七章]成本管理

成本管理知识体系&#xff1a; 规划成本管理&#xff1a; 估算成本&#xff1a; 制定预算&#xff1a; 控制成本&#xff1a; 7.1 挣值管理新兴实践 ps&#xff1a;了解即可&#xff0c;考试考不到 7.2 规划成本管理 定义&#xff1a;确定如何估算、预算、管理、监督和控制项目…

直接插入排序

一、概念及其介绍 插入排序(InsertionSort)&#xff0c;一般也被称为直接插入排序。 对于少量元素的排序&#xff0c;它是一个有效的算法。插入排序是一种最简单的排序方法&#xff0c;它的基本思想是将一个记录插入到已经排好序的有序表中&#xff0c;从而一个新的、记录数增…

你是否曾经为自己写的代码而感到懊恼?那如何才能写出高质量代码呢?

这里写目录标题 一、 前言二、高质量代码的特征三、编程实践技巧1. 遵循编码规范2. 使用有意义的变量名和函数名3. 减少代码重复4. 使用注释5. 编写单元测试6. 使用设计模式7. 使用版本控制工具8. 保持代码简洁9. 优化代码性能10. 学习和借鉴他人的代码总结 一、 前言 写出高质…

Python入门教程+项目实战-11.5节: 程序实战-选择排序算法

目录 11.5.1 排序算法简介 11.5.2 选择排序算法 11.5.3 系统学习python 11.5.1 排序算法简介 所谓排序&#xff0c;是指将数据集合中的元素按从小到大的顺序进行排列&#xff0c;或按从大到小的顺序进行排列。前者称为升序排序&#xff0c;后者称为降序排序。在数据结构与算…