题解 | 大数乘法

大数乘法

https://www.nowcoder.com/practice/c4c488d4d40d4c4e9824c3650f7d5571

解法1:模拟

我们可以模拟两个整数相乘的过程。两个整数相乘的过程其实就是一个数与另一个数的每一位分别相乘,最后将每一位乘的结果加起来即可。例如:12*23 = 276,我们可以先用12*3 + 12*20结果依旧是276.所以我们可以将这个模拟过程实现出来。

1.依次取出一个数的每一位,与另一个数相乘。但要注意的是,与每一位相乘时要注意其倍数,而不能只乘该位对应的数字。但倍数只会影响结果后的0的个数,所以我们只需要给与每一个相乘的结果后面加上对应个数的0即可。solve和_solve实现的功能

2.我们得到每一位的结果之后,需要相加,而这其实就是大数相加。逆序遍历,模拟竖式相加即可。addTwoString实现的功能

class Solution
{
public:
    string _solve(string s, int multiplier, string multiple)// 被乘数,乘数,倍数
    {
        string ret;
        int carry = 0;
        for (int i = s.size() - 1; i >= 0 || carry; --i)
        {
            int x = i >= 0 ? s[i] - '0' : 0;
            carry += x * multiplier;
            ret += to_string(carry % 10);
            carry /= 10;
        }
        reverse(ret.begin(), ret.end());

        return ret + multiple; // 补零
    }

    string addTwoString(string s, string t)
    {
        if (!s.size() || !t.size())
            return !s.size() ? t : s;

        int i = s.size() - 1, j = t.size() - 1, carry = 0;
        string ret;
        while (i >= 0 || j >= 0 || carry)
        {
            carry += i < s.size() ? s[i--] - '0' : 0;
            carry += j < t.size() ? t[j--] - '0' : 0;
            ret += to_string(carry % 10);
            carry /= 10;
        }
        reverse(ret.begin(), ret.end());
        return ret;
    }

    string solve(string s, string t)
    {
        if (s[0] == '0' || t[0] == '0')
            return "0";

        // 依次取出s的每一位 与 t相乘
        string multiple; // 倍数,与个位乘是不补零,十位补一个......
        int tmp = 0;
        string ret;
        for (int i = s.size() - 1; i >= 0; --i)
        {
            tmp = (s[i] - '0'); // 取出每一位
            ret = addTwoString(ret, _solve(t, tmp, multiple));
            multiple += '0'; //下一个是十位,提前补零
        }
        return ret;
    }
};

解法2:无进位相乘

做法就是我们直接模拟竖式相乘,但是不管进位,直接存储下来,且对应位置的还应该加在一起,最后统一处理进位,让每个位置只保留一个数。下面模拟一个示例:

根据示例,我们需要存储下对应位置的乘积的和,而且这些乘积的位置是由规律的,逆序相乘,下标从0开始,那么两个数乘积的位置就在i+j处。所以我们创建一个vector用来存储对应位置的乘积的和,最后在对vector里面的数进行进位处理。进位处理时同时要考虑carry!=0的情况。

因为我们是逆序进行操作的,vector里面也是逆序存储的,按照上面的例子来说应该是72 87 21,所以最后还需要进行逆序。但是逆序前还得进行一步——处理前导零。因为我们开的vector空间比较大,但是存储时可能存储不完,就可能导致后面多余了0,我们需要将这些0给删除掉,之后再进行逆置。

class Solution 
{
public:
    string solve(string s, string t) 
    {
        if(s[0] == '0' || t[0] == '0')
            return "0";

        // 1.逆置后无进位相乘相加
        reverse(s.begin(), s.end());
        reverse(t.begin(), t.end());

        int n = s.size() , m = t.size();
        vector<int> add_no_carry(n+m);
        for(int i=0; i<n; ++i)
        {
            for(int j=0; j<m; ++j)
            {
                add_no_carry[i+j] += (s[i] - '0') * (t[j] - '0');        
            }
        }

        // 2.处理进位
        string ret;
        int carry = 0;
        for(auto e : add_no_carry)
        {
            carry += e;
            ret += carry % 10 + '0';
            carry /= 10;
        }

        // 数组处理完后,carry有可能还需要处理进位
        while(carry)
        {
            ret += carry % 10 + '0';
            carry /= 10;
        }

        // 3.处理前导零
        if(ret.back() == '0') ret.pop_back();
        reverse(ret.begin(), ret.end());

        return ret;
    }
};

全部评论

相关推荐

AI牛可乐:哇塞,恭喜恭喜!48万的年薪,真是让人羡慕呀!看来你找到了一个超棒的工作,可以享受不卷的生活啦!🎉有没有什么求职秘诀想要分享给小牛牛呢?或者,想不想知道我是谁呢?😉(点击我的头像,我们可以私信聊聊哦~)
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务