剑指offer----C语言版----第十二天

news2024/12/23 4:16:32

目录

打印从1到最大的n位数

1.1 题目描述

1.2 Leetcode上的解题思路

1.3 考虑大数的问题

1.3.1 使用字符串模拟数字的加法

1.3.2 使用全排


打印从1到最大的n位数

原题链接:
剑指 Offer 17. 打印从1到最大的n位数 - 力扣(LeetCode)

1.1 题目描述

输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。

1.2 Leetcode上的解题思路

这道题目看起来很简单。我们看到这个问题之后,最容易想到的办法是先求出最大的n 位数,然后从1到最大的数赋值到数组中的对应下标即可。最大值怎么算嘞:假设输入3, 最大的三位数999 = 10 ^ 3 - 1。好的,代码如下:

int* printNumbers(int n, int* returnSize){
    int max = (int)pow(10, n) - 1;
    *returnSize = max;
    int*arr = (int*)malloc(sizeof(int)*max);
    int i;
    for(i = 0; i < max; i++)
    {
        arr[i] = i+1;
    }
    return arr;
}

1.3 考虑大数的问题

leetcode上返回的是一个int类型的数组,显然默认了数值并不会超过int类型的存储范围。但是既然是剑指offer上的题,肯定是不可能不考虑大数的问题滴。由于leetcode上无法进行测试,我就在Visual Studio 上演示结果哈!!!

1.3.1 使用字符串模拟数字的加法

在用字符串表示数字的时候,最直观的方法就是字符串里每个字符都是0'~"9"之间的某一个字符,用来表示数字中的一位。因为数字最大是n 位的,因此我们需要一个长度为n+1 的字符串(字符串中最后一位是结束符号"0')。当实际数字不够n 位的时候,在字符串的前半部分补0。首先把字符串中的每一个数字都初始化为0,然后每一次为字符串表示的数字加1,再打印出来。因此,我们只需要做两件事:

一是在字符串表达的数字上模拟加法;

二是把字符串表达的数字打印出来。

(1):在字符串表达的数字上模拟加法:(假设字符串的开头存高位)

我们需要知道什么时候停止在number上增加1,即什么时候到了最大的n 位数“999..99”(n 个9)。一个最简单的办法是在每次递增之后,都调用库函数 strcmp比较表示数字的字符串number和最大的n 位数“999..99”,如果相等则表示已经到了最大的n 位数并终止递增。虽然调用strcmp 很简单,但对于长度为 n 的字符串,它的时间复杂度为 O(n)。

我们注意到只有对“999...99”加1 的时候,才会在第一个字符(下标为0)的基础上产生进位,而其他所有情况都不会在第一个字符上产生进位。因此,当我们发现在加1 时第一个字符产生了进位,则已经是最大的n 位数,此时我们终止循环即可。

具体方法如下:

(2):将字符串表达的数字打印出来

接下来我们再考虑如何打印用字符串表示的数字。虽然库函数 printf可以很方便地打印出一个字符串,但在本题中调用 printf并不是最合适的解决方案。前面我们提到,当数字不够n位的时候,在数字的前面补0,打印的时候这些补位的0不应该打印出来。比如输入3 的时候,数字 98 用字符串表示成“098”。如果直接打印出 098,就不符合我们的阅读习惯。为此,我们定义了函数 printStr,在这个函数里,只有在碰到第一个非0 的字符之后才开始打印,直至字符串的结尾。

bool isOverflow(char* str, int n)
{
    //假设没有超过
    bool overflow = false;
    //是否进位
    int carry = 0;
    for (int i = n - 1; i >= 0; i--)
    {
        //将字符转化为数字
        int num = str[i] - '0' + carry;
        //个位加1
        if (i == n - 1)
        {
            num++;
        }
        //判断各位加1是否大于9
        if (num > 9)
        {
            //加1产生进位
            //判断是哪一位产生进位
            if (i == 0)
            {
                //如果下标为0的数字产生了进位,改变overflow
                overflow = true;
            }
            else
            {
                //不是下标为0的数字产生进位
                num -= 10; 
                carry = 1; //进位1
                str[i] = '0' + num; //将数字转回字符
            }

        }
        else
        {
            //加1没产生进位
            str[i] = '0' + num; //将数字转为字符
            //加一完成后退出循环
            break;
        }

    }
    //返回判断结果
    return overflow;

}


void printStr(char* str)
{
    //如果指向了不为0的字符改为true,就可以继续打印啦
    bool begin = false;
    char* temp = str;
    while (*temp)
    {
        if (*temp != '0' || begin)
        {
            begin = true;
            printf("%c", *temp);
        }
        temp++;
    }
    printf("\t");
}

void printNumbers(int n)
{
    //非法输入
    if (n <= 0)
    {
        return;
    }
    //开辟字符串存放数字,大小为n+1个char
    char* str = (char*)malloc(sizeof(char) * (n + 1));
    //将字符串初始化为字符0
    memset(str, '0', n);
    //添加字符串的结束字符\0
    str[n] = '\0';

    //循环打印, 当没有超出最大的n位数继续打印
    while (!isOverflow(str, n))
    {
        printStr(str);
    }
    free(str);
    str = NULL;
}

int main()
{

    printNumbers(2);
    return 0;
}

1.3.2 使用全排

上述思路虽然比较直观,但由于模拟了整数的加法,代码有点长。接下来我们换一种思路来考虑这个问题。如 果我们在数字前面补0,就会发现n位所有十进制数其实就是n个从0到n个9 的全排列。也就是说,我们把数字的每一位都从 0 到9 排列一遍,就得到 了所有的十进制数。只是在打印的时候,排在前面的0不打印出来罢了。

全排列用递归很容易表达,数字的每一位都可能是0~9 中的一个数, 然后设置下一位。递归结束的条件是我们已经设置了数字的最后一位。

此递归函数的作用是,首先排列最高位(最高位依然下标为0),排列最高位的时候递归进到下标为1的位置进行排列,进到下标为1的位置时,同样递归到下标为2的位置进行排列,以此类推直到满足递归结束的条件,递去归来的过程不理解还是画图哈!这道题还是比较简单的。

void printStr(char* str)
{
    //如果指向了不为0的字符改为true,就可以继续打印啦
    bool begin = false;
    char* temp = str;
    while (*temp)
    {
        if (*temp != '0' || begin)
        {
            begin = true;
            printf("%c", *temp);
        }
        temp++;
    }
    printf("\t");
}


void recurison(char* str, int n, int index)
{
    //如果数字的排到了最高位,则结束递归
    if (index == n - 1)
    {
        //打印此次排列好的数字
        printStr(str);
        return;
    }

    for (int i = 0; i < 10; i++)
    {
        //对输入的index的下一位进行1-9的全排列
        str[index + 1] = i + '0';
        //递归到下一位
        recurison(str, n, index + 1);
    }
}

void printNumbers(int n)
{
    //非法输入
    if (n <= 0)
    {
        return;
    }
    //开辟字符串存放数字,大小为n+1个char
    char* str = (char*)malloc(sizeof(char) * (n + 1));

    //添加字符串的结束字符\0
    str[n] = '\0';

    for (int i = 0; i < 10; i++)
    {
        //将数字转化为字符
        str[0] = i + '0';
        //进入递归尝试递归下一位
        recurison(str, n, 0);
    }

    free(str);
    str = NULL;
}


int main()
{

    printNumbers(3);
    return 0;
}

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

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

相关文章

算法刷题打卡第58天:删除排序链表中的重复元素

删除排序链表中的重复元素 难度&#xff1a;简单 给定一个已排序的链表的头 head &#xff0c;删除所有重复的元素&#xff0c;使每个元素只出现一次。返回已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2]示例 2&#xff1a; 输入…

Cesiumlab对人工模型、建筑矢量面和BIM模型的处理参数设置 CesiumLab系列教程

CesiumLab中将人工模型&#xff08;fbx、obj&#xff09;、建筑矢量面&#xff08;shp&#xff09;和BIM模型&#xff08;clm&#xff09;的处理都集中在一起&#xff0c;统一使用通用模型处理。 输入文件部分&#xff0c;加载文件在这里不在赘述&#xff0c;输入了文件后&…

陪诊系统搭建,陪诊平台应当具备什么功能?

随着近些年来市场的变化&#xff0c;陪诊服务也在慢慢的受到人们的关注&#xff0c;自从有了陪诊系统之后&#xff0c;帮助了许许多多独立就医不便的人群&#xff0c;给了像是搞不清就诊流程的老年人、家人不方便陪伴的孕妇、残障人士&#xff0c;以及需要陪伴就医的独居人士等…

上海市“专精特新”中小企业和杨浦区“专精特新”中小企业给予5万元和3万元资助

杨浦区“专精特新”中小企业认定一、主管部门杨浦区商务委员会二、政策依据《关于印发<杨浦区“专精特新”中小企业培育工程实施办法>的通知》&#xff08;杨商务委规〔2018〕1号&#xff09;《关于组织推荐2021年度杨浦区“专精特新”中小企业申报(复核)的通知》三、扶持…

【Qt】加载.ui转化的.h头文件显示窗体

【Qt】加载.ui转化的.h头文件显示窗体1、背景2、实例3、验证1、背景 将.ui文件转化为.h头文件参考如下博客&#xff1a; 【Qt】将QtDesigner生成的.ui文件转化为.h头文件 https://jn10010537.blog.csdn.net/article/details/128589666其中生成的ui_widget.h头文件内容如下&am…

TensorFlow之超级参数调优

Keras技术框架提供工具类库&#xff0c;用于对TensorFlow程序相关的超级参数进行调优&#xff0c;为机器学习选择正确的超级参数集合的过程被称之为超级参数调优。 超级参数是指用于治理一个机器学习模型的训练过程及其拓扑结构的变量&#xff0c;这些变量在整个训练过程中保持…

尚医通-项目启动过程

1.先启动Redis&#xff1a; redis-server redis.conf & 2.启动docker&#xff1a; systemctl start docker 3.进入mongo容器&#xff1a; docker exec -it mymongo /bin/bash 4.使用MongoDB客户端进行操作 mongo 5.启动nginx&#xff1a;cmd 输入命令nginx 前期使…

【Kotlin】空安全 ③ ( 手动空安全管理 | 非空断言操作符 !! | 使用 if 语句判空 )

文章目录一、非空断言操作符 !!二、使用 if 语句判空一、非空断言操作符 !! Kotlin 中的 可空类型 变量 , 在运行时 可以选择 不启用 安全调用 操作 , 在调用 可空类型 变量 成员 与 方法 时 , 使用 非空断言操作符 !! , 如果 可空类型 变量为 空 , 则 直接抛出 空指针异常 K…

部署k8s集群

环境准备准备三台虚拟机&#xff0c;建议最小硬件配置&#xff1a;2核CPU、2G内存、20G硬盘 &#xff0c;可以访问外网&#xff0c;&#x1f4a1;ps&#xff1a;以下命令在三台虚拟机上都要执行一遍&#xff0c;直到kubeadm init设置虚拟机hostname sudo hostnamectl set-hostn…

性能优化系列之『混合式开发:小程序内核及优势介绍』

文章の目录一、愿景二、技术优势三、底层内核四、行业背景五、选型建议写在最后一、愿景 触手可及&#xff1a;用户扫一扫或者搜一下即可打开应用用完即走&#xff1a;不用关心是否安装太多应用 二、技术优势 H5 相比 App 开发&#xff0c;开发门槛更低优于 H5&#xff0c;接…

指针进阶篇(1)

目录 &#x1f914; 前言&#x1f914; 一、&#x1f60a;字符指针&#x1f60a; 二、&#x1f61c;指针数组&#x1f61c; 三、&#x1f61d;数组指针&#x1f61d; 3.1数组指针的定义 3.2&数组名VS数组名 3.3数组指针的使用 四、&#x1f31d;数组参数&#xff0c…

LeetCode算法之----回溯

目录 【一】前言 【二】全排列 【三】电话号码的字母组合 【四】括号生成 【五】组合总和 【六】子集 【七】总结 【一】前言 回溯算法采用试错的思想&#xff0c;尝试分步的来解决一个问题。在分步解决问题的过程中&#xff0c;当它通过尝试发现现有的分步答案不能得到有效的…

helm、k8s dasboard、rancher、kubesphere介绍及使用

文章目录1. helm 安装及使用概述1.1 helm 安装1.1.1 添加仓库1.2 helm 常用命令2. dashboard 部署使用2.1 安装helm repo 源2.2 安装dashboard2.3 查看dashboard 运行状态2.4 创建dashboard-admin.yaml文件2.5 创建登录用户2.6 查看admin-user账户的token2.7 登录dashboard2.8 …

非对称加密实战(二):解决web项目不支持https问题 ,添加证书【附源码】

目录web项目http请求变为https请求解决无法访问https问题重启再次访问https出现链接不安全,但是可以继续访问认证文件加入域名参数生成客户端认证文件证书安装源码地址web项目 http请求变为https请求 http请求 https请求 解决无法访问https问题 需要把 非对称加密实战(一…

【博客576】警惕docker本身iptables规则对网络的影响

警惕docker本身iptables规则对网络的影响 警惕1&#xff1a;k8s环境下&#xff0c;独立拉取docker容器时&#xff0c;进行端口映射会有问题 场景&#xff1a; 在k8s节点由于某种原因&#xff0c;比如&#xff1a;需要拉起一个docker环境来制作镜像&#xff0c;需要拉起一些不…

靶机测试Os-hacknos-3笔记

靶机介绍Difficulty: IntermediateFlag: 2 Flag first user And the second rootLearning: Web Application | Enumeration | Privilege EscalationWeb-site: www.hacknos.comContact-us : rahul_gehlautThis works better with VirtualBox rather than VMware靶机地址https://…

nuPlan: A closed-loop ML-based planning benchmark for autonomous vehicles

Paper name nuPlan: A closed-loop ML-based planning benchmark for autonomous vehicles Paper Reading Note URL: https://arxiv.org/pdf/2106.11810.pdf TL;DR nuPlan 比赛&#xff0c;提出了规控领域新数据集 Introduction 背景 当前自动驾驶规划任务中使用专家系统…

正确实践Jetpack SplashScreen API —— 在所有Android系统上使用总结,内含原理分析

1.前言 文章末尾有演示的APK链接&#xff0c;感兴趣的同学&#xff0c;可以自行下载体验一下 官方Android 12的Splash Screen文档地址 官方Splash Screen兼容库&#xff0c;支持所有版本系统 本篇文章主要围绕下面三个问题来介绍&#xff1a; 我们能从Android 12 SplashScree…

订单数据越来越多,如何优化数据库性能?

“增删改查”都是查找问题&#xff0c;因为你都得先找到数据才能对数据做操作。那存储系统性能问题&#xff0c;其实就是查找快慢问题。 存储系统一次查询所耗时间取决两个因素&#xff1a; 查找的时间复杂度数据总量 查找的时间复杂度取决于&#xff1a; 查找算法存储数据…

基于Java-SpringBoot+vue实现的前后端分离信息管理系统设计和实现

基于Java-SpringBootvue实现的前后端分离信息管理系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言…