📜  用于表示为字符串的大十进制数的快速乘法的 Karatsuba 算法

📅  最后修改于: 2022-05-13 01:56:08.531000             🧑  作者: Mango

用于表示为字符串的大十进制数的快速乘法的 Karatsuba 算法

给定两个数字字符串AB ,任务是有效地找到两个数字字符串的乘积。

例子:

方法:给定的问题可以使用 Karastuba 的快速乘法算法来解决,这个想法是在整数前面附加零,这样两个整数都有相等的偶数位数n 。此后,按以下方式划分数字:

  • 因此,乘积A * B也可以表示为:

请注意,上面的表达式只需要三个乘法Al*BlAr*Br(Al + Ar)*(Bl + Br) ,而不是标准的四个。因此,递归变为T(n) = 3T(n/2) + O(n)并且此递归的解为O(n 1.59 ) 。这个想法在这篇文章中得到了更彻底的讨论。因此,可以使用以下步骤解决上述问题:

  • 创建一个函数findSum() ,该函数查找表示为字符串的两个大数的总和。类似地,创建一个函数findDiff() ,它找出两个表示为字符串的大数的差。
  • 在使用 Karatsuba 算法将数字相乘的递归函数multiply(A, B)中,首先在AB前面附加零,以使其位数相等且偶数。
  • 然后计算上面定义的AlArBlBr的值,并递归地找到multiply(Al, Bl)multiply(Ar, Br)multiply((Al + Ar), (Bl + Br)的值)并将它们的值代入上述推导出的方程。
  • 从方程中删除前导零后,打印方程的答案。

下面是上述方法的实现:

C++
// C++ progrram for the above approach
  
#include 
using namespace std;
  
// Function to find the sum of larger
// numbers represented as a string
string findSum(string str1, string str2)
{
    // Before proceeding further, make
    // sure length of str2 is larger
    if (str1.length() > str2.length())
        swap(str1, str2);
  
    // Stores the result
    string str = "";
  
    // Calculate length of both string
    int n1 = str1.length();
    int n2 = str2.length();
  
    // Reverse both of strings
    reverse(str1.begin(), str1.end());
    reverse(str2.begin(), str2.end());
  
    int carry = 0;
    for (int i = 0; i < n1; i++) {
  
        // Find the sum of the current
        // digits and carry
        int sum
            = ((str1[i] - '0')
               + (str2[i] - '0')
               + carry);
        str.push_back(sum % 10 + '0');
  
        // Calculate carry for next step
        carry = sum / 10;
    }
  
    // Add remaining digits of larger number
    for (int i = n1; i < n2; i++) {
        int sum = ((str2[i] - '0') + carry);
        str.push_back(sum % 10 + '0');
        carry = sum / 10;
    }
  
    // Add remaining carry
    if (carry)
        str.push_back(carry + '0');
  
    // Reverse resultant string
    reverse(str.begin(), str.end());
  
    return str;
}
  
// Function to find difference of larger
// numbers represented as strings
string findDiff(string str1, string str2)
{
    // Stores the result of difference
    string str = "";
  
    // Calculate length of both string
    int n1 = str1.length(), n2 = str2.length();
  
    // Reverse both of strings
    reverse(str1.begin(), str1.end());
    reverse(str2.begin(), str2.end());
  
    int carry = 0;
  
    // Run loop till small string length
    // and subtract digit of str1 to str2
    for (int i = 0; i < n2; i++) {
  
        // Compute difference of the
        // current digits
        int sub
            = ((str1[i] - '0')
               - (str2[i] - '0')
               - carry);
  
        // If subtraction < 0 then add 10
        // into sub and take carry as 1
        if (sub < 0) {
            sub = sub + 10;
            carry = 1;
        }
        else
            carry = 0;
  
        str.push_back(sub + '0');
    }
  
    // Subtract the remaining digits of
    // larger number
    for (int i = n2; i < n1; i++) {
        int sub = ((str1[i] - '0') - carry);
  
        // If the sub value is -ve,
        // then make it positive
        if (sub < 0) {
            sub = sub + 10;
            carry = 1;
        }
        else
            carry = 0;
  
        str.push_back(sub + '0');
    }
  
    // Reverse resultant string
    reverse(str.begin(), str.end());
  
    // Return answer
    return str;
}
  
// Function to remove all leading 0s
// from a given string
string removeLeadingZeros(string str)
{
    // Regex to remove leading 0s
    // from a string
    const regex pattern("^0+(?!$)");
  
    // Replaces the matched value
    // with given string
    str = regex_replace(str, pattern, "");
    return str;
}
  
// Function to multiply two numbers
// using Karatsuba algorithm
string multiply(string A, string B)
{
    if (A.length() > B.length())
        swap(A, B);
  
    // Make both numbers to have
    // same digits
    int n1 = A.length(), n2 = B.length();
    while (n2 > n1) {
        A = "0" + A;
        n1++;
    }
  
    // Base case
    if (n1 == 1) {
  
        // If the length of strings is 1,
        // then return their product
        int ans = stoi(A) * stoi(B);
        return to_string(ans);
    }
  
    // Add zeros in the beginning of
    // the strings when length is odd
    if (n1 % 2 == 1) {
        n1++;
        A = "0" + A;
        B = "0" + B;
    }
  
    string Al, Ar, Bl, Br;
  
    // Find the values of Al, Ar,
    // Bl, and Br.
    for (int i = 0; i < n1 / 2; ++i) {
        Al += A[i];
        Bl += B[i];
        Ar += A[n1 / 2 + i];
        Br += B[n1 / 2 + i];
    }
  
    // Recursively call the function
    // to compute smaller product
  
    // Stores the value of Al * Bl
    string p = multiply(Al, Bl);
  
    // Stores the value of Ar * Br
    string q = multiply(Ar, Br);
  
    // Stores value of ((Al + Ar)*(Bl + Br)
    // - Al*Bl - Ar*Br)
    string r = findDiff(
        multiply(findSum(Al, Ar),
                 findSum(Bl, Br)),
        findSum(p, q));
  
    // Multiply p by 10^n
    for (int i = 0; i < n1; ++i)
        p = p + "0";
  
    // Multiply s by 10^(n/2)
    for (int i = 0; i < n1 / 2; ++i)
        r = r + "0";
  
    // Calculate final answer p + r + s
    string ans = findSum(p, findSum(q, r));
  
    // Remove leading zeroes from ans
    ans = removeLeadingZeros(ans);
  
    // Return Answer
    return ans;
}
  
// Driver Code
int main()
{
    string A = "74638463789";
    string B = "35284567382";
  
    cout << multiply(A, B);
  
    return 0;
}


输出:
2633585904851937530398

时间复杂度: O(N log 3 ) 或 O(N 1.59 ),其中 N 是给定字符串A 和 B 的长度中的最大值。
辅助空间: O(N 2 )