Given two numeric strings A and B, the task is to find the product of the two numeric strings efficiently.
Example:
Input: A = 5678, B = 1234 Output: 7006652
Input: A = 74638463789, B = 35284567382 Output: 2633585904851937530398
Approach: The given problem can be solved using Karastuba’s Algorithm for Fast Multiplication, the idea is to append zeroes in front of the integers such that both the integers have an equal and even number of digits n. Thereafter, divide the numbers in the following way:
A = Al * 10n/2 + Ar [Al and Ar contain leftmost and rightmost n/2 digits of A] B = Bl * 10n/2 + Br [Bl and Br contain leftmost and rightmost n/2 digits of B]
- Therefore, the product A * B can also be represented as follows:
A * B = (Al * 10n/2 + Ar) * (Bl * 10n/2 + Br) => A * B = 10n*Al*Bl + 10n/2*(Al*Br + Bl*Ar) + Ar*Br => A * B = 10n*Al*Bl + 10n/2*((Al + Ar)*(Bl + Br) – Al*Bl – Ar*Br) + Ar*Br [since Al*Br + Bl*Ar = (Al + Ar)*(Bl + Br) – Al*Bl – Ar*Br]
Notice that the above expression only requires three multiplications Al*Bl, Ar*Br, and (Al + Ar)*(Bl + Br), instead of the standard four. Hence, the recurrence becomes T(n) = 3T(n/2) + O(n) and solution of this recurrence is O(n1.59). This idea has been discussed more thoroughly in this article. Therefore the above problem can be solved using the steps below:
- Create a function findSum(), which finds the sum of two large numbers represented as strings. Similarly, create a function findDiff(), which finds the difference of two large numbers represented as strings.
- In the recursive function multiply(A, B), which multiplies the numbers using Karatsuba’s Algorithm, firstly append zeroes in front of A and B to make their digit count equal and even.
- Then calculate the values of Al, Ar, Bl, and Br as defined above and recursively find the values of multiply(Al, Bl), multiply(Ar, Br), and multiply((Al + Ar), (Bl + Br)) and plug their values in the above-derived equation.
- Print the answer to the equation after removing the leading zeroes from it.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
string findSum(string str1, string str2)
{
if (str1.length() > str2.length())
swap(str1, str2);
string str = "" ;
int n1 = str1.length();
int n2 = str2.length();
reverse(str1.begin(), str1.end());
reverse(str2.begin(), str2.end());
int carry = 0;
for ( int i = 0; i < n1; i++) {
int sum
= ((str1[i] - '0' )
+ (str2[i] - '0' )
+ carry);
str.push_back(sum % 10 + '0' );
carry = sum / 10;
}
for ( int i = n1; i < n2; i++) {
int sum = ((str2[i] - '0' ) + carry);
str.push_back(sum % 10 + '0' );
carry = sum / 10;
}
if (carry)
str.push_back(carry + '0' );
reverse(str.begin(), str.end());
return str;
}
string findDiff(string str1, string str2)
{
string str = "" ;
int n1 = str1.length(), n2 = str2.length();
reverse(str1.begin(), str1.end());
reverse(str2.begin(), str2.end());
int carry = 0;
for ( int i = 0; i < n2; i++) {
int sub
= ((str1[i] - '0' )
- (str2[i] - '0' )
- carry);
if (sub < 0) {
sub = sub + 10;
carry = 1;
}
else
carry = 0;
str.push_back(sub + '0' );
}
for ( int i = n2; i < n1; i++) {
int sub = ((str1[i] - '0' ) - carry);
if (sub < 0) {
sub = sub + 10;
carry = 1;
}
else
carry = 0;
str.push_back(sub + '0' );
}
reverse(str.begin(), str.end());
return str;
}
string removeLeadingZeros(string str)
{
const regex pattern( "^0+(?!$)" );
str = regex_replace(str, pattern, "" );
return str;
}
string multiply(string A, string B)
{
if (A.length() > B.length())
swap(A, B);
int n1 = A.length(), n2 = B.length();
while (n2 > n1) {
A = "0" + A;
n1++;
}
if (n1 == 1) {
int ans = stoi(A) * stoi(B);
return to_string(ans);
}
if (n1 % 2 == 1) {
n1++;
A = "0" + A;
B = "0" + B;
}
string Al, Ar, Bl, 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];
}
string p = multiply(Al, Bl);
string q = multiply(Ar, Br);
string r = findDiff(
multiply(findSum(Al, Ar),
findSum(Bl, Br)),
findSum(p, q));
for ( int i = 0; i < n1; ++i)
p = p + "0" ;
for ( int i = 0; i < n1 / 2; ++i)
r = r + "0" ;
string ans = findSum(p, findSum(q, r));
ans = removeLeadingZeros(ans);
return ans;
}
int main()
{
string A = "74638463789" ;
string B = "35284567382" ;
cout << multiply(A, B);
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
public static String findSum(String str1, String str2) {
if (str1.length() > str2.length()) {
String temp = str1;
str1 = str2;
str2 = temp;
}
String str = "" ;
int n1 = str1.length();
int n2 = str2.length();
str1 = new StringBuilder(str1).reverse().toString();
str2 = new StringBuilder(str2).reverse().toString();
int carry = 0 ;
for ( int i = 0 ; i < n1; i++) {
int sum = ((str1.charAt(i) - '0' ) + (str2.charAt(i) - '0' ) + carry);
str += ( char )(sum % 10 + '0' );
carry = sum / 10 ;
}
for ( int i = n1; i < n2; i++) {
int sum = ((str2.charAt(i) - '0' ) + carry);
str += ( char )(sum % 10 + '0' );
carry = sum / 10 ;
}
if (carry != 0 )
str += ( char )(carry + '0' );
str = new StringBuilder(str).reverse().toString();
return str;
}
static String findDiff(String str1, String str2) {
String str = "" ;
int n1 = str1.length(), n2 = str2.length();
StringBuilder sb1 = new StringBuilder(str1);
StringBuilder sb2 = new StringBuilder(str2);
sb1 = sb1.reverse();
sb2 = sb2.reverse();
str1 = sb1.toString();
str2 = sb2.toString();
int carry = 0 ;
for ( int i = 0 ; i < n2; i++) {
int sub = ((str1.charAt(i) - '0' ) - (str2.charAt(i) - '0' ) - carry);
if (sub < 0 ) {
sub = sub + 10 ;
carry = 1 ;
} else
carry = 0 ;
str += sub;
}
for ( int i = n2; i < n1; i++) {
int sub = ((str1.charAt(i) - '0' ) - carry);
if (sub < 0 ) {
sub = sub + 10 ;
carry = 1 ;
} else
carry = 0 ;
str += sub;
}
str = new StringBuilder(str).reverse().toString();
return str;
}
public static String removeLeadingZeros(String str) {
String pattern = "^0+(?!$)" ;
str = str.replaceAll(pattern, "" );
return str;
}
public static String multiply(String A, String B) {
if (A.length() > B.length()) {
String temp = A;
A = B;
B = temp;
}
int n1 = A.length(), n2 = B.length();
while (n2 > n1) {
A = "0" + A;
n1++;
}
if (n1 == 1 ) {
int ans = Integer.parseInt(A) * Integer.parseInt(B);
return Integer.toString(ans);
}
if (n1 % 2 == 1 ) {
n1++;
A = "0" + A;
B = "0" + B;
}
String Al = "" , Ar = "" , Bl = "" , Br = "" ;
for ( int i = 0 ; i < n1 / 2 ; ++i) {
Al += A.charAt(i);
Bl += B.charAt(i);
Ar += A.charAt(n1 / 2 + i);
Br += B.charAt(n1 / 2 + i);
}
String p = multiply(Al, Bl);
String q = multiply(Ar, Br);
String r = findDiff( multiply(findSum(Al, Ar), findSum(Bl, Br)), findSum(p, q));
for ( int i = 0 ; i < n1; ++i)
p = p + "0" ;
for ( int i = 0 ; i < n1 / 2 ; ++i)
r = r + "0" ;
String ans = findSum(p, findSum(q, r));
ans = removeLeadingZeros(ans);
return ans;
}
public static void main(String[] args) {
String A = "74638463789" ;
String B = "35284567382" ;
System.out.println(multiply(A, B));
}
}
|
Python3
import re
def findSum(str1, str2):
if len (str1) > len (str2):
str1, str2 = str2, str1
result = ""
n1, n2 = len (str1), len (str2)
str1, str2 = str1.zfill(n2), str2.zfill(n2)
carry = 0
for i in range (n2 - 1 , - 1 , - 1 ):
sum_val = ( int (str1[i]) - 0 ) + ( int (str2[i]) - 0 ) + carry
result = str (sum_val % 10 + 0 ) + result
carry = sum_val / / 10
if carry:
result = str (carry + 0 ) + result
return result
def findDiff(str1, str2):
result = ""
n1, n2 = len (str1), len (str2)
str1, str2 = str1.zfill(n2), str2.zfill(n2)
carry = 0
for i in range (n2 - 1 , - 1 , - 1 ):
sub = ( int (str1[i]) - 0 ) - ( int (str2[i]) - 0 ) - carry
if sub < 0 :
sub + = 10
carry = 1
else :
carry = 0
result = str (sub + 0 ) + result
return result
def removeLeadingZeros(s):
pattern = "^0+(?!$)"
s = re.sub(pattern, "", s)
return s
def multiply(A, B):
if len (A) < 10 or len (B) < 10 :
return str ( int (A) * int (B))
n = max ( len (A), len (B))
n2 = n / / 2
A = A.zfill(n)
B = B.zfill(n)
Al, Ar = A[:n2], A[n2:]
Bl, Br = B[:n2], B[n2:]
p = multiply(Al, Bl)
q = multiply(Ar, Br)
r = multiply(findSum(Al, Ar), findSum(Bl, Br))
r = findDiff(r, findSum(p, q))
return removeLeadingZeros(findSum(findSum(p + '0' * n, r + '0' * n2), q))
if __name__ = = "__main__" :
A = "74638463789"
B = "35284567382"
print (multiply(A, B))
|
C#
using System;
using System.Linq;
using System.Text;
class GFG {
public static string FindSum( string str1, string str2)
{
if (str1.Length > str2.Length) {
string temp = str1;
str1 = str2;
str2 = temp;
}
string str = "" ;
int n1 = str1.Length;
int n2 = str2.Length;
str1 = new string (str1.Reverse().ToArray());
str2 = new string (str2.Reverse().ToArray());
int carry = 0;
for ( int i = 0; i < n1; i++) {
int sum = ((str1[i] - '0' ) + (str2[i] - '0' )
+ carry);
str += ( char )(sum % 10 + '0' );
carry = sum / 10;
}
for ( int i = n1; i < n2; i++) {
int sum = ((str2[i] - '0' ) + carry);
str += ( char )(sum % 10 + '0' );
carry = sum / 10;
}
if (carry != 0)
str += ( char )(carry + '0' );
return new string (str.Reverse().ToArray());
}
static string FindDiff( string str1, string str2)
{
string str = "" ;
int n1 = str1.Length, n2 = str2.Length;
str1 = new string (str1.Reverse().ToArray());
str2 = new string (str2.Reverse().ToArray());
int carry = 0;
for ( int i = 0; i < n2; i++) {
int sub = ((str1[i] - '0' ) - (str2[i] - '0' )
- carry);
if (sub < 0) {
sub = sub + 10;
carry = 1;
}
else
carry = 0;
str += sub;
}
for ( int i = n2; i < n1; i++) {
int sub = ((str1[i] - '0' ) - carry);
if (sub < 0) {
sub = sub + 10;
carry = 1;
}
else
carry = 0;
str += sub;
}
return new string (str.Reverse().ToArray());
}
public static string RemoveLeadingZeros( string input)
{
int i = 0;
while (i < input.Length && input[i] == '0' ) {
i++;
}
return i == input.Length ? "0" : input.Substring(i);
}
public static string Multiply( string A, string B)
{
if (A.Length > B.Length) {
string temp = A;
A = B;
B = temp;
}
int n1 = A.Length, n2 = B.Length;
while (n2 > n1) {
A = "0" + A;
n1++;
}
if (n1 == 1) {
return Convert.ToString(Convert.ToInt32(A)
* Convert.ToInt32(B));
}
if (n1 % 2 == 1) {
n1++;
A = "0" + A;
B = "0" + B;
}
string Al = "" , Ar = "" , Bl = "" , 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];
}
string p = Multiply(Al, Bl);
string q = Multiply(Ar, Br);
string r = FindDiff(
Multiply(FindSum(Al, Ar), FindSum(Bl, Br)),
FindSum(p, q));
for ( int i = 0; i < n1; ++i)
p = p + "0" ;
for ( int i = 0; i < n1 / 2; ++i)
r = r + "0" ;
string ans = FindSum(p, FindSum(q, r));
ans = RemoveLeadingZeros(ans);
return ans;
}
public static void Main( string [] args)
{
string A = "74638463789" ;
string B = "35284567382" ;
Console.WriteLine(Multiply(A, B));
}
}
|
Javascript
function findSum(str1, str2) {
if (str1.length > str2.length) {
[str1, str2] = [str2, str1];
}
let str = '' ;
let n1 = str1.length;
let n2 = str2.length;
str1 = str1.split( '' ).reverse().join( '' );
str2 = str2.split( '' ).reverse().join( '' );
let carry = 0;
for (let i = 0; i < n1; i++) {
let sum = parseInt(str1[i]) + parseInt(str2[i]) + carry;
str += (sum % 10).toString();
carry = Math.floor(sum / 10);
}
for (let i = n1; i < n2; i++) {
let sum = parseInt(str2[i]) + carry;
str += (sum % 10).toString();
carry = Math.floor(sum / 10);
}
if (carry) {
str += carry.toString();
}
return str.split( '' ).reverse().join( '' );
}
function findDiff(str1, str2) {
let str = '' ;
let n1 = str1.length;
let n2 = str2.length;
str1 = str1.split( '' ).reverse().join( '' );
str2 = str2.split( '' ).reverse().join( '' );
let carry = 0;
for (let i = 0; i < n2; i++) {
let sub = parseInt(str1[i]) - parseInt(str2[i]) - carry;
if (sub < 0) {
sub += 10;
carry = 1;
} else {
carry = 0;
}
str += sub.toString();
}
for (let i = n2; i < n1; i++) {
let sub = parseInt(str1[i]) - carry;
if (sub < 0) {
sub += 10;
carry = 1;
} else {
carry = 0;
}
str += sub.toString();
}
return str.split( '' ).reverse().join( '' );
}
function removeLeadingZeros(str) {
return str.replace(/^0+/, '' );
}
function multiply(A, B) {
if (A.length == 1 || B.length == 1) {
return (parseInt(A) * parseInt(B)).toString();
}
let maxLength = Math.max(A.length, B.length);
let splitPosition = Math.floor(maxLength / 2);
let Al = A.substring(0, A.length - splitPosition);
let Ar = A.substring(A.length - splitPosition);
let Bl = B.substring(0, B.length - splitPosition);
let Br = B.substring(B.length - splitPosition);
let p = multiply(Al, Bl);
let q = multiply(Ar, Br);
let r = multiply(findSum(Al, Ar), findSum(Bl, Br));
r = findDiff(r, findSum(p, q));
for (let i = 0; i < 2 * splitPosition; i++) {
p += '0' ;
}
for (let i = 0; i < splitPosition; i++) {
r += '0' ;
}
let ans = findSum(p, findSum(q, r));
ans = removeLeadingZeros(ans);
return ans;
}
let A = "74638463789" ;
let B = "35284567382" ;
console.log(multiply(A, B));
|
Output
2633585904851937530398
Time Complexity: O(Nlog 3) or O(N1.59), where N is the maximum among the lengths given strings A and B. Auxiliary Space: O(N2)
|