大数加法,一个思路秒杀三个题 | 字符串相加、两数之和、字符串相乘

前言

本博客是保姆级的大数加法思路剖析,带你使用大数加法的思路,AC以下三道题:415. 字符串相加LCR 025. 两数相加 II43. 字符串相乘,由于限制了用一种思路去解三道题。看完这篇博客之后,可以帮助你激发解决大数四则运算的思路。

什么是大数加法

大数加法主要解决的是两个非常大的数(超过了基本数据类型能表示的范围)相加的问题。在计算机中,基本数据类型(如int、long等)有固定的位数,因此它们能表示的数值范围是有限的。当需要处理的数值超过了这个范围时,就需要使用特殊的算法来实现大数的加法。即使用stringlist等容器存储数字,再模拟竖式计算的过程,得到最终的答案。

415. 字符串相加 - 力扣(LeetCode)

在这里插入图片描述

这道题是大数加法的模版题,AC思路就是上文提到过的模拟竖式计算,整个过程分为两步:

基本循环

如图所示,在没有进位的情况下,分别遍历两个字符串,将同位的数字相加,得数便是得数该位的结果。

char类型与int类型的数字转换公式:

  • int型 = char型 - ‘0’
  • char型 = int型 + ‘0’

在这里插入图片描述

处理进位

我们会遇到两个地方要对进位进行处理

  • 当基本循环的两个同位数之和大于10,就会进位到下一位。
  • 上一位的进位要加入到基本循环中。

所以得数的某一位的公式可以总结为:str1对应位 + str2对应位 + 进位 = 该位得数,然后再用一个变量存储进位即可。记得得数最后一位也要检查进位变量

在这里插入图片描述

string addStrings(string num1, string num2) {
    	//从低位开始遍历
        int i1=num1.size()-1,i2=num2.size()-1;
        string res;
        int next=0;
        while(i1>=0 || i2>=0){
            int temp=0,n1=-1,n2=-1;
            if(i1==-1){
                n1=0;
            }
            else{
                n1=num1[i1]-'0';
                i1--;
            }

            if(i2==-1){
                n2=0;
            }
            else{
                n2=num2[i2]-'0';
                i2--;
            }

            //每一位的组成为:
            //num1对应位+num2对应位+进位
            temp=n1+n2+next;
            
            char ch=temp%10+'0';
            next=temp/10;

            res+=ch;
            
        }
    `	//检查进位变量
        if(next)
            res+='1';
            
        reverse(res.begin(),res.end());
        return res;
    }

LCR 025. 两数相加 II - 力扣(LeetCode)

在这里插入图片描述

有了大数加法的基础,对于这样类似竖式计算的题,很容易就能有思路:遍历链表,将链表转为用string表示,然后直接用大数加法计算得出结果,最后将结果再转为链表。(虽然这个方法不是最优解,但如果用STL库中的迭代器区间构造,代码量是比较少的)

参考代码:

ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* cur1 = l1;
        ListNode* cur2 = l2;
        string str1;
        string str2;
        while (cur1) {
            str1 += cur1->val + '0';
            cur1 = cur1->next;
        }
        while (cur2) {
            str2 += cur2->val + '0';
            cur2 = cur2->next;
        }
        string temp = addString(str1, str2);	//addstring就是刚才的字符串加法
        ListNode* ans = new ListNode(temp[0] - '0');
        ListNode* cur = ans;
        for (int i = 1; i < temp.size(); i++) {
            int num = temp[i] - '0';
            ListNode* Node = new ListNode(num);
            cur->next = Node;
            cur = cur->next;
        }
        return ans;
    }

当然,我觉得反转链表后,再模拟竖式计算是最优解,少了官方解答或是大数加法的stack或string的额外空间消耗。可以自己尝试实现一下!

43. 字符串相乘 - 力扣(LeetCode)

在这里插入图片描述

如果想用大数加法的思路解决这道题,就要想起乘法的本质:“n*m”表示n个m相加的和。这样就将乘法过程转化为了加法过程,我们就能直接用大数加法的接口去解决这道题:

string multiply(string num1, string num2) {
        if(num1=="0"||num2=="0")
            return "0";
            
        string res,cot("0");
        while(cot != num1){
            cout<<cot<<endl;
            cot=addStrings(cot,"1");
            res=addStrings(res,num2);
        }
        return res;
}

当然,这样做是会超时的,因为“n个”的n是大数,进行n次相加必然超时,所以需要优化我们的代码。

我们还是拆解为n个数相加,但尝试模拟实现竖式乘法的过程,我们让n变为另一个数字的一位,那么n将小于等于9。结果处再补0即可。

在这里插入图片描述

在这里插入图片描述

这样优化之后,我们最多进行200*9次大数加法,便能得出最终的结果。

参考代码(最优解还是得完全用乘法模拟过程,但这里就不给出参考代码了):

	string multiply(string num1, string num2) {
        if(num1=="0"||num2=="0")
            return "0";
            
        int i1=num1.size()-1,i2=num2.size()-1;
        string res;
        for(int i=0;i<num2.size();i++){
            int n=num2[num2.size()-i-1]-'0';
            string temp=_addstirng(num1,n);
            
            for(int j=i;j>0;j--){
                //补足最后的‘0’
                temp.push_back('0');
            }
            res=addStrings(res,temp);
        }
        return res;
    }

	string _addstirng(string num1, int n){
        string res;
        while(n){
            res=addStrings(res,num1);	//addString为模版的大数加法
            n--;
        }
        return res;
    }

谢谢你的阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值