【一刷《剑指Offer》】面试题 12:打印 1 到最大的 n 位数

devtools/2024/9/19 5:24:01/ 标签: 剑指Offer, 算法, 字符串, 大数, 递归, 全排列, dfs

力扣对应题目链接:LCR 135. 报数 - 力扣(LeetCode)

牛客对应题目链接:打印从1到最大的n位数_牛客题霸_牛客网 (nowcoder.com)


一、《剑指Offer》内容


二、分析题目

1、暴力解法


2、用字符串模拟数字加法

  • 首先要考虑当 n 很大时(比如:100),打印出来的数很有可能是超过 INT_MAX 的范围,所以我们用字符串来表示每个数。
  • 当然,在这一题中,由于返回的是一个 int 型的数组,所以是不可能超过 INT_MAX 的,但是一般大数问题都不会要求返回 int 数组来保存每一位数,而是循环输出每一位数。
  • 思路:假设 n=3,定义一个字符串,初始化为 "000",然后用它来循环模拟从 1 到最大的 n 位数,并循环保存到 int 数组中(在真实情况下则是循环输出)。

3、递归全排列解法

假设 n=3,要输出的数其实就是三位数的全排列(000,001,002,...,999。注意:000 不能输出),用递归来表示出这个过程即可。


三、代码

1、暴力解法

//写法一
class Solution {
private:vector<int> res;
public:vector<int> countNumbers(int cnt) {int n=1;while(cnt--)n*=10;for(int i=1; i<n; i++)res.push_back(i);return res;}
};//写法二
class Solution {
private:vector<int> res;
public:vector<int> countNumbers(int cnt) {for(int i=1; i<pow(10, cnt); i++)res.push_back(i);return res;}
};//写法三
class Solution {
private:vector<int> res;
public:vector<int> countNumbers(int cnt) {string maxValue;while(cnt--)maxValue+='9';for(int i=1; i<=stoi(maxValue); i++)res.push_back(i);return res;}
};

2、用字符串模拟数字加法

class Solution {
private:vector<int> res;
public:bool increment(string& s){bool isOverflow = false;int carry = 0;for (int i = s.size() - 1; i >= 0; i--){int cur = s[i] - '0' + carry;if (i == s.size() - 1)cur++;if (cur >= 10){if (i == 0)isOverflow = true;else{carry = 1;s[i] = cur - 10 + '0';}}else{s[i] = cur + '0';break;}}return isOverflow;}void printNumbers(string& s){bool isBeginningZero = true;string tmp;for (int i = 0; i < s.size(); i++){if (isBeginningZero && s[i] != '0')isBeginningZero = false;if (!isBeginningZero)tmp += s[i];}res.push_back(stoi(tmp));}vector<int> countNumbers(int cnt) {if (cnt <= 0) return res;string s(cnt, '0');while (!increment(s))printNumbers(s);return res;}
};

3、递归全排列解法

class Solution {
private:vector<int> res;
public:void printNumbers(string& s){bool isBeginningZero = true;string tmp;for (int i=0; i<s.size(); i++){if(isBeginningZero && s[i]!='0')isBeginningZero=false;if(!isBeginningZero)tmp+=s[i];}if(tmp!="") res.push_back(stoi(tmp));}void permutation(string& s, int length, int index){if(index==length-1){printNumbers(s);return;}for(int i=0; i<10; i++){s[index+1]=i+'0';permutation(s, length, index+1);}}vector<int> countNumbers(int cnt) {if(cnt<=0) return res;string s(cnt, '0');for(int i=0; i<10; i++){s[0]=i+'0';permutation(s, cnt, 0);}return res;}
};

四、扩展

在前面的代码中,我们都是用一个 char 型字符表示十进制数字的一位。8 个 bit 的 char 型字符最多能表示 256 个字符,而十进制数字只有 0~9 的 10 个数字。因此用 char 型字符串来表示十进制的数字并没有充分利用内存,造成了一些浪费。

有没有更高效的方式来表示大数

通过使用 string 进行求解(上面的方法都可以转换成 string 来求解,下面写一个 dfs)。

  • 第一层遍历 n,1 位数、2 位数、3 位数...
  • 因为第一位数不能取 0,所以第一位数单独拉出来遍历,故第二层遍历 1~9,代表第一位数只能取 1~9
  • 然后 dfs,遍历 2~n 的每一位数字,取值范围 0~9

注意:无需回溯,因为保存结果的是 string,不用引用传递就行。

dfs 的过程:

  • k 表示当前是第 k 个位置,当 k=n 时,dfs 终止,将 string 保存。
  • 当前位置可选 0~9,然后 dfs 下一个位置。
//大数解法(dfs)
class Solution {
private:vector<int> res;
public:void dfs(int k, int n, string s){if(k==n){res.push_back(stoi(s));return;}for(int i=0; i<10; i++)dfs(k+1, n, s+to_string(i));}vector<int> countNumbers(int cnt) {for(int i=1; i<=cnt; i++)for(int j=1; j<10; j++)dfs(1, i, to_string(j));return res;}
};

五、相关题目

定义一个函数,在该函数中可以实现任意两个整数的加法。由于没有限定输入两个数的大小范围,我们也要把它当作大数来处理。在第一个思路中,实现了在字符串表示的数字上加 1 的功能,可以参考这个思路实现两个数字的相加功能。另外还有一个需要注意的问题:

如果输入的数字中有负数,我们应该怎么去处理?

通常对于大数问题,常用的方法就是使用字符串来表示这个大数。可以先将两个整数分别用字符串来表示,然后分别将这两个字符串拆分成对应的字符数组。当两个整数都是正数的时候直接相加结果为正数,同为负数的时候取两者的绝对值相加然后在结果前加一个负号。如果是一正一负,则用两者的绝对值相减,用绝对值大的数减去绝对值小的数,当正数的绝对值大的时候相减的结果为正数,当负数的绝对值大的时候相减的结果为负数,结果为负数时在相减的结果前加一个负号即可。在具体进行相加的时候两个字符数组对应的数字字符相加即可,当有进位的时候做出标记,在更高一位进行相加时再将这个进位加进去。

tips:如果面试题是关于 n 位的整数并且没有限定 n 的取值范围,或者是输入任意大小的整数,那么这个题目很有可能是需要考虑大数问题的。字符串是一个简单、有效的表示大数的方法。


http://www.ppmy.cn/devtools/32909.html

相关文章

IoTDB 入门教程 基础篇⑦——数据库管理工具 | DBeaver 连接 IoTDB

文章目录 一、前文二、下载iotdb-jdbc三、安装DBeaver3.1 DBeaver 下载3.2 DBeaver 安装 四、安装驱动五、连接数据库六、参考 一、前文 IoTDB入门教程——导读 二、下载iotdb-jdbc 下载地址org/apache/iotdb/iotdb-jdbc&#xff1a;https://maven.proxy.ustclug.org/maven2/o…

【数学建模】矩阵微分方程

一、说明 我相信你们中的许多人都熟悉微分方程&#xff0c;或者至少知道它们。微分方程是数学中最重要的概念之一&#xff0c;也许最著名的微分方程是布莱克-斯科尔斯方程&#xff0c;它控制着任何股票价格。 ​​ 股票价格的布莱克-斯科尔斯模型 微分方程可以由数学中的许多…

MyBatisPlus @TableLogic实现全局自动逻辑删除

一、背景 有一天&#xff0c;小王在编写代码时实现了一个删除操作&#xff0c;但由于测试场景覆盖不全&#xff0c;上线后不慎删除了系统中的部分业务数据。幸运的是&#xff0c;系统已经开启了binlog日志功能&#xff0c;使得我们能够根据日志来恢复这些误删的数据。这一事故…

关于测试用例

目录 一 测试用例介绍 二 写用例的好处 三 不适合写用例的情况 一 测试用例介绍 测试用例由测试来写&#xff0c;编写时间在需求评审和设计评审&#xff08;如有&#xff09;结束后&#xff0c;需求提测前&#xff0c;用例依赖需求文档来编写。一般包含用例标题&#xff0c…

算法提高之二维费用的背包问题

算法提高之二维费用的背包问题 核心思想&#xff1a;二维01背包 每个物品只能用一次 所以是01背包模板用f[j][k] 表示第一维费用不超过V 第二维费用不超过M的方案 #include <iostream>#include <cstring>#include <algorithm>using namespace std;const i…

OneFlow深度学习框原理、用法、案例和注意事项

本文将基于OneFlow深度学习框架&#xff0c;详细介绍其原理、用法、案例和注意事项。OneFlow是由中科院计算所自动化研究所推出的深度学习框架&#xff0c;专注于高效、易用和扩展性强。它提供了一种类似于深度学习库的接口&#xff0c;可以用于构建神经网络模型&#xff0c;并…

R和Python市场篮分析算法及行为分析模型

&#x1f3af;要点 行为数据分析&#xff1a;&#x1f3af;线性统计研究生学业表现&#xff1a;&#x1f58a;绘制测试分数配对图 | &#x1f58a;构建简单线性回归模型&#xff0c;拟合数据 | &#x1f58a;构建多线性回归&#xff0c;三维可视化数据拟合模型 | &#x1f58a…

前端 JS 异常那些事

前言 人无完人&#xff0c;所以代码总会出异常的&#xff0c;异常并不可怕&#xff0c;关键是怎么处理 什么是异常 程序发生了意想不到的情况&#xff0c;影响到了程序的正确运行 从根本上来说&#xff0c;异常就是一个普通的对象&#xff0c;其保存了异常发生的相关信息&a…

《Maven》linux中安装maven并配置环境变量

阿丹&#xff1a; 很多项目需要在服务器上使用maven来打包&#xff0c;这里就需要使用配置maven来进行运行指令&#xff0c;本文章来快速的安装和配置一下这个Maven并且来完成环境变量的配置。 步骤 1: 安装Maven 在Linux系统上安装Maven: 如果你使用的是基于Debian的系统&a…

Codeforces Round 942 (Div. 2) (A-D2)C++题解

链接 : Dashboard - Codeforces Round 942 (Div. 2) - Codeforces A. Contest Proposal 数据范围小&#xff0c;模拟就好了; #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define endl \n #define int long long typedef l…

ASP.NET网上车辆档案管理系统

摘 要 本文采用基于Web的Asp.net技术&#xff0c;并与sql server 2000数据库相结合&#xff0c;研发了一套车辆档案管理系统。该系统扩展性好&#xff0c;易于维护。简化了车辆档案设计流程&#xff0c;去除了冗余信息。汽车销售企业可以通过本系统完成整个销售及售后所有档案…

【Python】 逻辑回归:从训练到预测的完整案例

我把我唱给你听 把你纯真无邪的笑容给我吧 我们应该有快乐的 幸福的晴朗的时光 我把我唱给你听 用我炙热的感情感动你好吗 岁月是值得怀念的留恋的 害羞的红色脸庞 谁能够代替你呀 趁年轻尽情的爱吧 最最亲爱的人啊 路途遥远我们在一起吧 &#x1f3b5; 叶…

Redis 相关问题总结

Redis 相关问题 Redis 持久化机制 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题 热点数据和冷数据是什么 Memcache与Redis的区别都有哪些&#xff1f; 单线程的redis为什么这么快 redis的数据类型&#xff0c;以及每种数据类型的使用场景&#xff0c;Redis 内…

Git推送本地项目到gitee远程仓库

Git 是一个功能强大的分布式版本控制系统&#xff0c;它允许多人协作开发项目&#xff0c;同时有效管理代码的历史版本。开发者可以克隆一个公共仓库到本地&#xff0c;进行更改后将更新推送回服务器&#xff0c;或从服务器拉取他人更改&#xff0c;实现代码的同步和版本控制。…

力扣39(组合总和)

解题思路&#xff1a;没有什么特殊的&#xff0c;按照递归三部曲确定返回值与参数&#xff0c;确定终止条件&#xff0c;确定单层循环的逻辑就可以解出来 代码实现&#xff1a; class Solution { public: vector<vector<int>>result; vector<int>path; vo…

【苍穹外卖】项目实战Day04

&#x1f525; 本文由 程序喵正在路上 原创&#xff0c;CSDN首发&#xff01; &#x1f496; 系列专栏&#xff1a;苍穹外卖项目实战 &#x1f320; 首发时间&#xff1a;2024年5月5日 &#x1f98b; 欢迎关注&#x1f5b1;点赞&#x1f44d;收藏&#x1f31f;留言&#x1f43e…

Uniapp软件库全新带勋章功能(包含前后端源码)

源码介绍&#xff1a; Uniapp开发的软件库全新带勋章功能&#xff0c;搭建好后台 在前端找到 util 这个文件 把两个js文件上面的填上自己的域名&#xff0c;电脑需要下载&#xff1a;HBuilderX 登录账号 没有账号就注册账号&#xff0c; 然后上传文件&#xff0c;打包选择 “…

C++Linux系统编程——Linux基本命令(究极全)

1.Linux常见目录介绍 /&#xff1a;根目录&#xff0c;一般根目录下只存放目录&#xff0c;在Linux下有且只有一个根目录。所有的东西都是从这里开始。当你在终端里输入“/home”&#xff0c;你其实是在告诉电脑&#xff0c;先从/&#xff08;根目录&#xff09;开始&#xff0…

代码随想录-算法训练营day28【回溯04:复原IP地址、子集】

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客 28 第七章 回溯算法 ● 93.复原IP地址 ● 78.子集 ● 90.子集II 详细布置 93.复原IP地址 本期本来是很有难度的&#xff0c;不过 大家做完 分割回文串 之后&#xff0c;本题就容易很多了 题目链接/文章讲解&#x…

【React】React-redux多组件间的状态传递

效果&#xff08;部分完整代码在最底部&#xff09;&#xff1a; 编写 Person 组件 上面的 Count 组件&#xff0c;已经在前面几篇写过了&#xff0c;也可以直接翻到最底部看 首先我们需要在 containers 文件夹下编写 Person 组件的容器组件 首先我们需要编写 index.jsx 文件…