LeetCode大数运算

415. 字符串相加


题意:给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。

返回值:返回相加后的结果字符串。

说明:

  • 1、num1 和num2 的长度都小于 5100
  • 2、num1 和num2 都只包含数字 0-9
  • 3、num1 和num2 都不包含任何前导零
  • 4、你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式

思路:

这道题主要考察对字符串的模拟,模拟两个整数相加的情况。

来看看我们做加法的情况。

在这里插入图片描述

步骤:

■ 1、从每个数从低位到高位依次相加,包括进位的数字。

■ 2、判断当前相加的数是否超过10,如果超过10往前进位,然后当前数减去10。

■ 3、循环步骤一和步骤二,直到把字符串遍历完。

■ 4、检查最后是否有进位,如果有进位,将进位加上,最后得到就是我们的结果。

提示:

■ 1、因为我们不确定最后结果的长度,所以我们常常将得到的每一位结果依次往结果字符串当中增加,这样得到的结果是反的,所以最后我们需要将结果字符串反转。

■ 2、我们处理每个字符串时,从最高位处理,最高位对应的是数字中的最低位。

C++ 代码

class Solution {
public:
    string addStrings(string num1, string num2) {
        string res;	//存储结果字符串
        int i=num1.size()-1,j=num2.size()-1,carry=0; //从最高位开始处理字符串
        while(i>=0||j>=0){
            if(i>=0) carry+=(num1[i]-'0');//分别检查每个字符串是否处理完
            if(j>=0) carry+=(num2[j]-'0');
            res.push_back((carry%10)+'0');//算得本位应该是多少
            carry/=10;	//算的是否进位
            i--,j--;
        }
        if(carray)res.push_back(carray+'0');//检查最后是否还有进位
        reverse(res.begin(),res.end());	//得到的结果是反的所以要将字符串反转,变成最终的结果
        return res;
    }
};

解决了这道题,可以去解决以下几道题:

1、LeetCode 445. 两数相加 II

2、LeetCode 66. 加一


高精度减法

题意:给定两个正整数,计算它们的差,计算结果可能为负数。

输入格式:共两行,每行包含一个整数。

输出格式:共一行,包含所求的差。

数据范围:1≤整数长度≤10^5

输入样例:

32
11

输出样例:

21

思路:

这道题主要考察对字符串的模拟,模拟两个整数相减的情况。

来看看我们做减法的情况。(和加法类似)

在这里插入图片描述

步骤:

■ 1、用大数的每一位数减去小数的每一位数,每个数从低位到高位依次相减,包括借位。

■ 2、判断当前每个位上的数相减是否小于0。如果小于0往前借一位数,然后当前数加上10,借位置成1。否则不借位,借位置成0。然后算得当前数的结果,存入结果字符串中。

■ 3、循环步骤一和步骤二,直到把字符串遍历完。

■ 4、检查最后字符串中是否包含前导0。如果存在去掉前导0,最后将结果字符串反转。

提示:

■ 1、因为我们不确定最后结果的长度,所以我们常常将得到的每一位结果依次往结果字符串当中增加,这样得到的结果是反的,所以最后我们需要将结果字符串反转。我们可以将输入的两个整数的每一位存入容器中来进行处理。

■ 2、我们处理每个字符串时,从最高位处理,最高位对应的是数字中的最低位。

C++ 代码

#include<iostream>
#include<vector>
using namespace std;

//return A>=B
bool cmp(vector<int>&A,vector<int>&B){
    if(A.size()!=B.size()) return A.size()>B.size();
    for(int i=A.size()-1;i>=0;i--){
        if(A[i]!=B[i])
            return A[i]>B[i];
    }
    return true;
}

vector<int> sub(vector<int>&A,vector<int>&B){
    vector<int> res;
    int temp=0;
    for(int i=0;i<A.size();i++){
        temp=A[i]-temp;
        if(i<B.size()) temp-=B[i];
        res.push_back((temp+10)%10);//当temp>0时,(temp+10)%10=temp。当temp<0,则(temp+10)为当前值,所以将两种情况合并了。
        if(temp<0) temp=1;//当temp<0表示借位。
        else temp=0;
    }
    while(res.size()>1&&res.back()==0) res.pop_back();//当情况为:999-999=000,所以去掉前导0
    return res; 
}
int main(){
    string a,b;
    cin>>a>>b;
    vector<int> A,B;
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    for(int i=b.size()-1;i>=0;i--) B.push_back(b[i]-'0');
    if(cmp(A,B)){
        vector<int> res=sub(A,B);
        for(int i=res.size()-1;i>=0;i--) printf("%d",res[i]); //反向输出,则为结果 
    }else{
        vector<int> res=sub(B,A);
        cout<<'-';
        for(int i=res.size()-1;i>=0;i--) printf("%d",res[i]);  
    }
    return 0;
}

解决了这道题,可以去解决 MiOJ 3. 大数相减(字符串减法)

43. 字符串相乘


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

返回值:返回相乘后的结果字符串。

说明:

  • 1、num1 和num2 的长度都小于 110
  • 2、num1 和num2 都只包含数字 0-9
  • 3、num1 和num2 均不以0开头,除非是0本身
  • 4、你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式

在这里插入图片描述

前言:

对于比较小的数字,我们可以直接将两个数字相乘得到结果。但是本道题的两个字符串的长度小于110,说明有可能达到100以上。所以直接用两数相乘,乘数都有可能无法保存,更不用说要保存结果了。那么我们只能手动模拟字符串相乘,请看以下模拟的情况:

在这里插入图片描述


对于手动模拟的思路是,先算789 * 2,再算789 * 50,对于789 * 50直接相当于789 * 5往后错一位。对于这个过程我们设计了乘法进位,和加法进位。对于三位数乘三位数,有三位数的取值范围为:[100,1000),所以三位数乘三位数的取值范围为:[10000,1000000)。有可能是五位数,有可能是六位数。我们要找到一套简单一致的规则来让计算机计算。我们看789 * 2,实质是:2 * 9 + 80 * 2 + 700 * 2789 * 50,实质是:50 * 9 + 80 * 9 + 700 * 9 。看以下根据本质计算的结果:

在这里插入图片描述


我们通过计算每个数字的每一位和另一个数字的每一位相乘,这样我们就只需要考虑加法和进位,最后加完每一位后就是最终结果了。

思路:

分别用两个指针( i,j )在两个数字(num1,num2)的每一位中循环。res=num1[i] * num2[j]。每次将结果累加到对应的位置。res对应的位置是str[i+j],str[i+j+1]。最后得出结果。

在这里插入图片描述

C++ 代码

class Solution {
public:
    string multiply(string num1, string num2) {
        if(num1=="0"||num2=="0") return "0";//当num1或者num2为0时直接返回0
        int len1=num1.size(),len2=num2.size();
        vector<int> vec(len1+len2);//初始化一个最大的结果容器,里面的内容全为0
        string res="";//存储结果
        int carry=0;
        for(int i=len1-1;i>=0;i--){
            for(int j=len2-1;j>=0;j--){
                int mul=(num1[i]-'0')*(num2[j]-'0');//每位相乘的结果
                int p1=i+j,p2=i+j+1;//相乘后应放到对应的结果[i+j,i+j+1]
                int sum=mul+vec[p2];//累加到sum上
                vec[p2]=sum%10;
                vec[p1]+=sum/10; //加上进位的结果进位
            }
        }
        for(int i=0;i<vec.size();i++){
            if(i==0&&vec[i]==0){
                continue;	//如果第一位为0 说明前缀没有使用,则去掉前缀为0的情况。
            }
            res.push_back(vec[i]+'0');
        }
        return res;
    }
};
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值