C++之大数运算

溪云初起日沉阁

山雨欲来风满楼


契子✨ 


我们知道数据类型皆有范围,一旦超出了这个范围就会造成溢出问题

今天说说我们常见的数据类型范围:

我们平时写代码也会遇到数据类型范围溢出问题:

比如 ~ 我们之前写的学生管理系统在用 int类型 填写学生学号时,我们发现了数据溢出

那么我们是怎么解决的呢?我们采用了 char* 类型 (数组)在我们 C++ 中也就是 string 类型

也就是我们可以用字符串类型存储较大的数(会溢出的数据)

而字符串的数学运算也被称为大数运算


废话不多说,铁铁们请看题:

字符串相加

题目链接:字符串相加


给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。

你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。

示例 1:

输入:num1 = "11", num2 = "123"
输出:"134"

示例 2:

输入:num1 = "456", num2 = "77"
输出:"533"

示例 3:

输入:num1 = "0", num2 = "0"
输出:"0"

提示:

  • 1 <= num1.length, num2.length <= 104
  • num1 和num2 都只包含数字 0-9
  • num1 和num2 都不包含任何前导零

题目分析: 

我们只需要对两个大整数模拟「竖式加法」的过程:

竖式加法就是我们平常学习生活中常用的对两个整数相加的方法,回想一下我们在纸上对两个整数相加的操作,是不是如下图将相同数位对齐,从低到高逐位相加,如果当前位和超过 10,则向高位进一位?我们只需按照这个思路来解决问题即可。

算法思想:

现在我们要考虑是从前往后加,还是从后往前加呢?如果是从前往后加则需要补 0 对齐,我们这里选择从后往前加。先定义两个指针 left、right 指向两个字符串 s1、s2 的末尾,再取出对应位置字符串的字符转化成 int整型 进行操作。最后将结果在转化为字符型并插入到字符串中。

注意:这里需要考虑进位问题,我们可以采用一个 next 变量来进行进位维护

如果 s1[left]+s2[right] >= 10,这个时候就需要进位了,简单暴力一点:

            next = (s1[left]+s2[right])/10;
            (s1[left]+s2[right]) %= 10;

对于我们的上一位数,我们选择直接加上 next 即可

代码测试:

class Solution 
{
public:
    string addStrings(string num1, string num2) 
    {
        int end1 = num1.size()-1;
        int end2 = num2.size()-1;
        string str;
        int next = 0;
        while(end1>=0 || end2>=0) //最长的字符串遍历完就结束
        {
            //转化成 int 类型进行数学运算,如果前面没有数据就自动补 0
            int x1 = end1>=0 ? num1[end1--] - '0':0;
            int x2 = end2>=0 ? num2[end2--] - '0':0;
            int x = x1+x2+next;
            //判断进位
            next = x/10;
            x %= 10;
            //转化成字符在进行头插
            str.insert(str.begin(),'0'+x);
        }
        if(next == 1)
        str.insert(str.begin(),'1');
        return str;
    }
};

 

注意:

        if(next == 1)
        str.insert(str.begin(),'1');

我们来看这个代码,为什么要加上这一行代码呢?

如果 x1 = 1,x2 = 9 那么只有 '0' 被插入字符串,因为最长字符串的长度为 1 只能进行一次循环,当退出循环时还没来的及进位就结束了!!!

时间复杂度分析:

设两字符串中最长的长度为 n,那么时间复杂度为 O(n^2)

因为一次遍历 + 头插,为了让时间效率更优一点,优化成 O(n),我们可以改成尾插:

class Solution 
{
public:
    string addStrings(string num1, string num2) 
    {
        int end1 = num1.size()-1;
        int end2 = num2.size()-1;
        string str;
        int next = 0;
        while(end1>=0 || end2>=0)
        {
            int x1 = end1>=0 ? num1[end1--] - '0':0;
            int x2 = end2>=0 ? num2[end2--] - '0':0;
            int x = x1+x2+next;
            next = x/10;
            x %= 10;
            str.push_back('0'+x);
        }
        if(next == 1)
        str.push_back('1');
        reverse(str.begin(), str.end());
        return str;
    }
};

字符串相乘

题目链接:字符串相乘


给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。

示例 1:

输入: num1 = "2", num2 = "3"
输出: "6"

示例 2:

输入: num1 = "123", num2 = "456"
输出: "56088"

提示:

  • 1 <= num1.length, num2.length <= 200
  • num1 和 num2 只能由数字组成。
  • num1 和 num2 都不包含任何前导零,除了数字0本身。

题目分析: 

<1>首先可以做一个小小的优化:先判断两个字符串是否含有 "0" ,如果有直接返回 "0" 即可

<2>如果两个字符串都不是 "0" ,则可以通过模拟「竖式乘法」的方法计算乘积。从右往左遍历乘数,将乘数的每一位与被乘数相乘得到对应的结果,再将每次得到的结果累加

 <3>假设 num1 和 num2 的长度分别为 n 和 m,则它们的乘积的长度最多为 n + m

我们可以申请一个长度为 m + n 的数组,用于存储乘积的每一位

从低位到高位,依次计算乘积的每一位,最后将数组转换为字符串即可

注意:判断最高位是否为 0,如果是,则去掉

代码展示: 

class Solution 
{
public:
    string multiply(string num1, string num2) 
    {
        if(num1 == "0"||num2 == "0")
            return "0";
        int n = num1.size(),m = num2.size();
        vector<int> arr(n+m);
        for(int i = n-1;i>=0;i--)
        {
            for(int j = m-1;j>=0;j--)
            {
                int a = num1[i] - '0';
                int b = num2[j] - '0';
                arr[i+j+1] += a*b;
            }
        }
        for(int i = arr.size()-1;i>0;i--)
        {
            arr[i-1] += arr[i]/10;
            arr[i] %= 10;
        }
        int i = 0;
        while(arr[i] == 0)
        {
            i++;
        }
        string str;
        for(i;i<arr.size();i++)
        {
            str += '0'+arr[i];
        }
    return str;
    }
};

 

注意:

arr[i+j+1] += a*b;

因为 i = n-1 和 j = m-1 即 i+j = n+m-2,所以现在的右边界为 n+m-1,左边界为 0,所以长度是 n+m ,没有越界

 

 注意:

int i = 0;
while(arr[i] == 0)
{
    i++;
}

判断最高位是否为 0,如果是,则去掉

有些时候的 num1 和 num2 并没有到达 m+n 的长度,但是前位就会自动补 "0",所以要判断

 

时间复杂度分析:

假设 n 是 num1 的长度,m 是 num2 的长度,时间复杂度为 O(m×n) -- 两层 for 循环

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学习笔记:IEEE 1003.13-2003(POSIX实时与嵌入式规范)

一、文档 在线参考&#xff1a; IEEE 1003.13-2003 免费下载Draft 版本&#xff08;pdf&#xff09;&#xff1a;IEEE Std. 1003.13 二、概念 1、POSIX标准 可移植操作系统接口&#xff08;英语&#xff1a;Portable Operating System Interface&#xff0c;缩写为POSIX&a…

第八届大数据与物联网国际会议(BDIOT 2024)即将召开!

第八届大数据与物联网国际会议(BDIOT 2024)将于2024年9月14-16日在澳门圣若瑟大学举行。数聚未来&#xff0c;物联世界&#xff01;BDIOT 2024旨在搭建为各位与会代表展示自己研究成果、分享经验、建立联系和开展合作的平台&#xff0c;共同探讨大数据与物联网领域的未来发展方…

PostgreSQL的学习心得和知识总结(一百四十一)|深入理解PostgreSQL数据库数据库角色的使用及预定义角色的原理

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

人工智能实验:人脸检测

一、实现目的&#xff1a; 了解人脸检测的主要方法&#xff1b;了解 detectMultiScale 函数的功能及用法&#xff1b;掌握使用 OpenCV 提供的分类器和检测器进行人脸检测的方法。 二、实验设备&#xff1a; 计算机一台&#xff1b;视觉实验软件环境及资源一套&#xff08;vi…

MySQL-----多表查询(二)

目录 一.子查询概述&#xff1a; 二&#xff1a;标量子查询&#xff1a; 三&#xff1a;列子查询&#xff1a; 四&#xff1a;行子查询&#xff1a; 五&#xff1a;表子查询&#xff1a; 六&#xff1a;练习部分&#xff1a; 写在之前&#xff1a;本文承接上文MySQL-----多…

万用板是什么?和印刷电路板一样吗?

同学们大家好&#xff0c;今天我们继续学习杨欣的《电子设计从零开始》&#xff0c;这本书从基本原理出发&#xff0c;知识点遍及无线电通讯、仪器设计、三极管电路、集成电路、传感器、数字电路基础、单片机及应用实例&#xff0c;可以说是全面系统地介绍了电子设计所需的知识…

Hikyuu-PF-银行股轮动交易策略实现

今天&#xff0c;带来的是“如何使用 Hikyuu 中的投资组合来实现银行股轮动交易策略”。 这个策略的逻辑很简单&#xff1a;持续持有两支市净率最低银行股&#xff0c;然后每月换仓 定义回测周期与回测标的 同样&#xff0c;首先定义回测周期&#xff1a; # 定义回测日期 …

基于Nios-II的流水灯

基于Nios-II的流水灯 一、Qsys设计&#xff08;一&#xff09;新建项目&#xff08;二&#xff09;Platfrom Designer&#xff08;三&#xff09;设置时钟主频&#xff08;四&#xff09;添加Nios-II Processor并设置&#xff08;五&#xff09;添加JTAG并配置&#xff08;六&a…

android_systemServer进程启动流程

一&#xff0c;systemServer进程是被Zygote进程fork出来的&#xff0c;具体代码&#xff0c; 在startBootstrapServices、startCoreServices、startOtherServices、startApexServices中&#xff0c;对各类服务进行了启动&#xff0c;比如我们常见的ActivityManagerService、Pa…

AI视频教程下载:用ChatGP在24小时内制作发布畅销电子书

这门变革性的课程使您能够利用内容生成和自行出版的新兴AI世界。利用ChatGPT 4等尖端人工智能工具&#xff0c;也称为ChatGPT Plus&#xff0c;您将获得所需的技能集&#xff0c;以创建引人入胜的内容&#xff0c;掌握设计&#xff0c;并成为亚马逊KDP上成功的自行出版作者 。 …

Parallels Desktop 19 for Mac v19.3.0.54924中文破解版

Parallels Desktop 19 for Mac v19.3.0.54924中文破解版是一款强大的虚拟机软件&#xff0c;支持多操作系统&#xff0c;提供卓越的虚拟化技术&#xff0c;确保流畅稳定的运行。新增特色功能如共享打印、TouchID集成等&#xff0c;提供便捷高效的虚拟机体验。界面美观现代&…

理解DPI:从数码到打印的深入分析

目录标题 1. DPI的定义2. DPI与图像质量2.1. 对于打印来说&#xff1a;2.2. 对于屏幕显示来说&#xff1a; 3. 如何计算DPI4. 调整DPI4.1. 提高DPI&#xff1a;4.2. 降低DPI&#xff1a; 5. DPI与图像文件大小的关系6. 实际应用中的DPI6.1. 专业打印&#xff1a;6.2. 屏幕设计&…

含义:理财风险等级R1、R2、R3、R4、R5

理财风险等级R1、R2、R3代表什么&#xff0c;为什么R1不保本&#xff0c;R2可能亏损 不尔聊投资https://author.baidu.com/home?frombjh_article&app_id1704141696580953 我们购买理财产品的时候&#xff0c;首先都会看到相关产品的风险等级。风险等级约定俗成有5级&…

谷歌十诫 Ten things we know to be true, Google‘s Core values

雷军曾经要求金山人人都必须能背谷歌十诫 我们所知的十件事 当谷歌刚成立几年时&#xff0c;我们首次写下了这“十件事”。我们时不时回顾这个列表&#xff0c;看看它是否仍然适用。我们希望它仍然适用——你也可以要求我们做到这点。 1. Focus on the user and all else wi…

三、Redis五种常用数据结构-Hash

Hash是redis中常用的一种无序数据结构。结构类似HashMap。 具体结构如下&#xff1a;key field value 1、优缺点 1.1、优点 同类数据归类整合储存&#xff0c;方便数据管理。相比于string操作消耗内存和CPU更小。分字段存储&#xff0c;节省网络流量。 1.2、缺点 过期时间…

Java数组的使用

前言 这里我使用的是IDEA编译器进行演示 数组的创建与初始化 创建格式&#xff1a; T[] 数组名 new T[N] T表示数组存放的数据类型&#xff0c;N表示数组的大小。 T[] 表示数组的类型。 这里要注意和C语言不同的是C语言使用类似int arr[10]这样的结构进行创建数组&#xff0c…

24V转3.8V用什么芯片方案-AH8310

在将24V降压至3.8V的电源转换中&#xff0c;AH8310是一个理想的选择。这款芯片是一款降压转换器&#xff0c;输入电压范围为4.5V至36V&#xff0c;输出电压可调&#xff0c;峰值电流可达1.5A。AH8310采用SOT23-6封装&#xff0c;内置MOS&#xff0c;适用于各种应用场合&#xf…

modprobe: can‘t open ‘modules.dep‘: No such file or directory

使用modprobe会提示modprobe: cant open modules.dep: No such file or directory 直接输入depmod即可。 如果depmod没有效果&#xff0c;则需要重新配置编译你的根文件。 在busybox配置界面进入linux Module Utilities, 上下键选择depmod&#xff0c;并按 y 选中&#xff0c…

【vue+vue-treeselect】根据指定字段,如isLeaf(是否末级节点),设置只允许末级节点可以选

1、当项目有特殊要求&#xff0c;必须根据某个字段的值去判断&#xff0c;是否节点可以选&#xff0c;即使已经是末级节点了&#xff0c;还是需要根据字段判断是否禁用 &#xff08;1&#xff09; :flat"true"一定要设置 (2)获取数据源的时候&#xff0c;设置下禁用…

leetcode91.解码方法(动态规划)

问题描述&#xff1a; 一条包含字母 A-Z 的消息通过以下映射进行了 编码 &#xff1a; A -> "1" B -> "2" ... Z -> "26" 要 解码 已编码的消息&#xff0c;所有数字必须基于上述映射的方法&#xff0c;反向映射回字母&#xff08;可…
最新文章