经典大数相加算法、高精度加法

经典大数相加算法、高精度加法

引言

先上一道题LC415.字符串相加

给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。


对于这道题,可能很多朋友会想到将两个字符转为数字,然后将其进行相加,最后将结果再转为字符串。这种方式可行,但是如果数字非常大呢?大到连long long 都不够加呢?那我们就得请出我们的主角:高精度加法

高精度加法是什么?

百科上的定义:高精度加法是信息学的一种重要算法。这种算法使用多个存储单位进行计算,因此它的计算范围超过一般使用一个存储单位的算法。所谓高精度加法,其实就是竖式加法,竖式加法我们在小学2年半的时候都学过,例如我要实现114 + 514,那就是:
竖式加法.jpg

如上图所示,我们从个位开始相加,4 + 4 = 8,然后到十位,1 + 1 = 2,接着到百位,1 + 5 = 6,所得结果就是628。所示例子没有进位,如果有进位的话,需要加上进位值。如9 + 3,需要进1,本位是2。

为什么需要高精度加法?

高精度加法原来就是所谓的竖式相加,这不是小学生都会吗?其实,高精度加法在计算机算法中有着重要的应用。我们知道,在C/C++语言中,通常来说(32位机器),int、long类型占32位,long long类型占64位,而最大的类型unsigned long long能表示的最大数也就才(1e19+8e18) ,如果要几百位的数来进行相加,那就不行了,所以,我们就可以使用高精度来计算,高精度一般也会用来处理大数相加的问题。

高精度加法实现(C++)

思路

我们将两个大数采用字符串的形式输入,然后模拟竖式加法的过程,用两个指针,先从个位开始相加(即字符串的最后一位),我们定义一个变量add来存进位值(如果没有进位则为0),然后逐步往高位移动,继续相加。考虑到两个数位数会有不一样的情况,有一个先加完,一个后加完,那我们采取将先加完的数的剩余位默认补0的方式即可,具体代码实现如下。

代码

class Solution {
public:
    string addStrings(string num1, string num2) {
        //从个位开始相加,初始化进位add为0
        int i = num1.length() - 1, j = num2.length() - 1, add = 0;
        string ans = "";//定义一个空字符串来拼接答案
        
        //当其中一个数没加完或者进位大于0时执行循环
        while(i >= 0 || j >= 0 || add > 0){
            //当前位数没有加完则为本身,加完的话则默认为补的0
            int x = i >= 0 ? num1[i] - '0' : 0;
            int y = j >= 0 ? num2[j] - '0' : 0;
            int result = x + y + add;
            
            //将当前位的值加入ans
            ans.push_back('0' + result % 10);
            
            //更新进位值
            add = result / 10;
            i--;
            j--;
        }
        
        //由于每一位插入时是尾插导致低位在前,翻转一下即可
        reverse(ans.begin(), ans.end());
        return ans;
    }
};
  • 时间复杂度:O(max(len1, len2)),其中len1和len2分别为两字符串的长度。
  • 空间复杂度:O(1),我们只需要常数空间来存储若干变量。

拓展

例题

LC67.二进制求和

LC2.两数相加

LC445.两数相加II


这里我们研究一下两数相加这题,题目如下:

LC2.两数相加
给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
add-two.png

思路分析

如果仔细看完高精度加法的内容的话,会发现,这也不还是相当于模拟加法的过程吗?只是存储形式从字符串变为了链表而已。我们先把两链表头看成最低位即个位,开始进行相加,同样我们也用一个变量add来存储进位值,接着进行下一个节点的相加,一直到链表为空,同样也是会有一个链表先走完的情况,那我们将先走完的剩下的空位补0即可

代码
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        //创建头指针和尾指针
        ListNode* head = nullptr, *tail = nullptr;
        
        //定义变量表示进位值,初始化为0
        int add = 0;
    
        //当其中一个链表不为空时或者进位值不为0时进行循环
        while(l1 || l2 || add > 0){
            int x = l1 ? l1 -> val : 0;
            int y = l2 ? l2 -> val : 0;
            int sum = x + y + add;
            
            //创建一个节点来存储相加后当前位的值
            ListNode* tmp = new ListNode(sum % 10);
            if(!head){
                head = tail = tmp;
            } else {
                tail -> next = tmp;
                tail = tail -> next;//更新tail
            }
            add = sum / 10;//更新进位值
            
            //迭代往下走
            if(l1) l1 = l1 -> next;
            if(l2) l2 = l2 -> next;
        }
        return head;
    }
};

高精度计算

我们在上面入门学习了高精度加法,即模拟竖式计算,也通过字符串相加,两数相加等题目对其有了更深的理解。那其实,有高精度加法,当然也有高精度减法、高精度乘法、高精度除法,其实本质上都是在模拟我们竖式计算的过程。而这些高精度计算的方法,为我们计算大数提供了可行方式,今后我们也会逐渐地深入学习和了解。

以上就是字符串相加、经典大数相加算法(高精度加法)入门的全部内容了,如果文章有什问题或者错误,或者有什么建议和想法,欢迎随时和我交流。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值