题解 | #大数乘法#

大数乘法

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

Python3复现算法书上的分治法,两个相乘的数A,B可以分解为
(A1*10^(n/2)+A2)*(B1*10^(n/2)+B2)=10^n*A1*B1+10^(n/2)*(A1*B2+A2*B1)+A2*B2  ,(1)
其中A1*B2+A2*B1=(A1+A2)*(B1+B2)-A1*B1-A2*B2 ,     (2)
可以看到,(2)相比于(1)少做了一次乘法,因此时间复杂度可以减为O(N^1.59)左右
算法基本思想如下:

算法伪代码如下:(图中用的2进制,我用的十进制)

#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param s string字符串 第一个整数
# @param t string字符串 第二个整数
# @return string字符串
#
class Solution:
    # 字符串乘法
    def solve(self, s: str, t: str) -> str:
        # write code here
        # 分治法
        num = max(len(s), len(t)) // 2
        # 递归出口
        if s == "" or t == "":
            return ""
        if num <= 2:
            return str(int(s) * int(t))

        # 将每个数字一分为2,(a*10^num+b)*(c*10^num+d)
        s_l, s_r = s[:-num], s[-num:]
        t_l, t_r = t[:-num], t[-num:]
        print(s_l, s_r)
        print(t_l, t_r)
        p1 = self.solve(s_l, t_l)  # a*c
        p2 = self.solve(s_r, t_r)  # b*d
        p3 = self.solve(self.str_add(s_l, s_r), self.str_add(t_l, t_r))  # (a+b)*(c+d)
        if p1 != "":
            res1 = self.add_zero(p1, num * 2)  # 10^n*(a*c)
        else:
            res1 = ""
        cun = self.str_sub(self.str_sub(p3, p1), p2)  # ((a+b)*(c+d)-a*c-b*d)
        res2 = self.add_zero(cun, num)  # 10^(n/2)*((a+b)*(c+d)-a*c-b*d)
        res = self.str_add(self.str_add(res1, res2), p2) # 10^n*(a*c)+10^(n/2)((a+b)*(c+d)-a*c-b*d)+b*d
        return res

    # 字符串加法
    def str_add(self, s: str, t: str) -> str:
        s = list(map(int, list(s)))  # 将s转化成数字数组
        s.reverse()  # 从低位开始计算
        t = list(map(int, list(t)))  # 将t转化为数字数组
        t.reverse()  # 从低位开始计算
        num = max(len(s), len(t)) + 1  # 最长串
        # 将两个串加0到等长
        for i in range(len(s) - 1, num):
            s.append(0)
        for i in range(len(t) - 1, num):
            t.append(0)
        carry = 0  # 进位
        res = [0] * num
        for i in range(num):
            cun = s[i] + t[i] + carry
            carry = (cun) // 10
            res[i] = str(cun % 10)
        # 去除多余的0
        while res[-1] == "0" and len(res) > 1:
            res.pop()
        res.reverse()
        return "".join(res)

    # 字符串减法
    def str_sub(self, s: str, t: str) -> str:
        # 大的减小的
        s = list(map(int, list(s)))  # 将s转化成数字数组
        s.reverse()  # 从低位开始计算
        t = list(map(int, list(t)))  # 将t转化为数字数组
        t.reverse()  # 从低位开始计算
        num = max(len(s), len(t)) + 1  # 最长串
        # 将两个串加0到等长
        for i in range(len(s) - 1, num):
            s.append(0)
        for i in range(len(t) - 1, num):
            t.append(0)
        carry = 0  # 借位
        res = [0] * num
        for i in range(num):
            cun = s[i] - t[i] - carry
            if cun < 0:
                # 不够借
                carry = 1
                cun += 10
            else:
                carry = 0
            res[i] = str(cun)
        # 去除多余的0
        while res[-1] == "0" and len(res) > 1:
            res.pop()
        res.reverse()
        return "".join(res)

    # 乘10的n次幂
    def add_zero(self, s: str, n) -> str:
        # 添加0,如s*10^n就是在s后面添加n个0
        s = list(s)
        res = "".join(s + ["0"] * n)
        return res

#分治进行递归#
全部评论

相关推荐

喜欢走神的孤勇者练习时长两年半:爱华,信华,等华,黑华
点赞 评论 收藏
分享
Noob1024:一笔传三代,人走笔还在
点赞 评论 收藏
分享
1 2 评论
分享
牛客网
牛客企业服务