leetcode——字符串相乘(C++)

12 篇文章 0 订阅


本篇文章将对leetcode的字符串相乘这一道题目进行讲解,题目链接如下:
43.字符串相乘


题目

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

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

提示:

  • num1num2都只能由数字组成且不包含前导0
  • 1 <= num1.length, num2.length <= 200
class Solution{
public:
	string multiply(string num1, string num2){
	
	}
}

分析

  • 首先,转换成int再进行相乘一定是不行的,题目所给的数据范围说明了这个数有可能是一个很大的数,大到超过long long 的数据范围
  • 所以要解这道题,我们只能是模拟我们做乘法的过程,这题也可以算是两个大数相乘的模板题。

思路

回忆一下小学我们是如何做两个数的乘法的(doge),让第一个数和第二个数的每一个数相乘,然后再不断的进位相加即可。

那么要编程实现这一过程,为了思路清晰,我们可以分模块实现
string mul(string& num1, int x
实现第一个数和一个小数相乘(第二个数的某一位)

void add(string& ans, string tmp, int k)
实现两个大数的进位相乘,其中k表示要进的位数,ans存储相加后的值。

重点

在实现两个大数相加的过程时,如果我们按照正常的思路从低位加到高位的话,很容易会发现想要确定最终答案string的长度是一件很麻烦的事,所以我们不难想到如果存在string内的数是相反的顺序,那么就对于string长度的确定问题就简单了很多,变成了一个较为易解的双指针问题,所以在mul函数返回的string应该是与答案相反的便于供add()使用。
如图:
在这里插入图片描述

实现

首先,先不写上面两个函数的实现逻辑,先把接口函数的大框架先搭出来,也就是整个模拟乘法的过程如下:

    string multiply(string num1, string num2) {
        string ans;
        int now = 1,k=0;
        //~i等价于i>=0
        //这是由于当i==-1时根据整型在内存中是补码的存储格式
        //-1在内存中的二进制格式为全一,取反就是0,表示结束循环
        for(int i = num2.size()-1; ~i; --i)
        //在答案string上以此进位加上num1和num2的每位数的相乘
        //k表示当前是进位到了第几位
        //每次相加之后,进位要增加,所以要k++
        //这里由于num2中存的时字符,所以化作整型时应该先减去字符'0'
            add(ans,mul(num1,num2[i]-'0'),k++);
        int end = ans.size()-1;
        //由于在存储中采用了倒序存储,所以有可能存在前导0
        //在输出答案时应该要先把前导0删去
        //但是要注意答案就是0的情况需要保留一个0
        while(end&&ans[end--]=='0') ans.pop_back();
        //逆置string得到答案
        reverse(ans.begin(),ans.end());
        return ans;
    }

string mul(string& num1, int x函数

    string mul(string& num1, int x)
    {
    	//如果乘数存在0,直接返回0即可
        if(x == 0) return "0";
        string tmp;
        //end1指向num1的最后一个数字,开始模拟乘法
        //top表示进位
        int top = 0, end1 = num1.size()-1;
        //与上面同理,表示end1>=0
        while(~end1)
        {
        //同样有字符和数字的转换问题
            int t = (num1[end1]-'0')*x+top;
            top = t/10;
            //利用尾插来达到将最终答案逆置的效果
            //记住答案也需要加上字符'0'
            tmp.push_back(char(t%10+'0'));
            --end1;
        }
        //如果最后进位不是0,仍然需要加上top
        if(top) return tmp + char(top+'0');
        else return tmp;
    }

void add(string& ans, string tmp, int k)函数

//由于mul的string是相反的答案
//所以add时只需要从前往后遍历即可
    void add(string& ans, string tmp, int k)
    {
    	//由于是进位加法,所以从ans的第k位才开始加
        int end1 = k, end2 = 0;
		//top表示进位
        int len1 = ans.size(), len2 = tmp.size();
        int top = 0;
        while(end1<len1||end2<len2)
        {
        	//先用t来保存该位数以及top相加之后的值
            int t = top;
            if(end1 < len1) t+=ans[end1] - '0';
            if(end2 < len2) t+=tmp[end2] - '0';
            top = t/10;
            //如果这时end1还没有到达最后,那么直接修改原数据即可
            if(end1< len1) ans[end1] = t%10+'0';
            //如果已经到达最后了,说明需要进行尾插
            else ans.push_back(char(t%10+'0')); 
            ++end1;++end2;
        }
        //一定要记得判断是否需要进位!!!
        if(top) ans.push_back('1');
    }

整体答案

class Solution {
public:
    string mul(string& num1, int x)
    {
        if(x == 0) return "0";
        string tmp;
        int top = 0, end1 = num1.size()-1;
        while(~end1)
        {
            int t = (num1[end1]-'0')*x+top;
            top = t/10;
            tmp.push_back(char(t%10+'0'));
            --end1;
        }
        if(top) return tmp + char(top+'0');
        else return tmp;
    }
    void add(string& ans, string tmp, int k)
    {
        int end1 = k, end2 = 0;
        int len1 = ans.size(), len2 = tmp.size();
        int top = 0;
        while(end1<len1||end2<len2)
        {
            int t = top;
            if(end1 < len1) t+=ans[end1] - '0';
            if(end2 < len2) t+=tmp[end2] - '0';
            top = t/10;
            if(end1< len1) ans[end1] = t%10+'0';
            else ans.push_back(char(t%10+'0')); 
            ++end1;++end2;
        }
        if(top) ans.push_back('1');
    }
    string multiply(string num1, string num2) {
        string ans;
        int now = 1,k=0;
        for(int i = num2.size()-1; ~i; --i)
        {
            //cout << mul(num1,num2[i]-'0')<<endl;
            add(ans,mul(num1,num2[i]-'0'),k++);
        }
        int end = ans.size()-1;
        //cout << end << endl;
        while(end&&ans[end--]=='0') ans.pop_back();
        reverse(ans.begin(),ans.end());
        return ans;
    }
};

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暮雨清秋.L

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值