【分治】用四种方式计算大数乘法

本文探讨了在计算机中处理大数运算的几种方法,包括传统的人工乘法、竖式优化的乘法、分而治之的策略以及不使用BigInteger类的解决方案。详细介绍了每种方法的实现思路,并提供了相应的代码示例,如字符串相加、相乘的实现,以及分治算法在大数乘法中的应用。这些方法展示了如何通过基本的数学原理和算法处理大整数的精确计算问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在计算机中,通常用int,long来存储整形数字,但由于空间问题,当数字过大时,long也存储不了。因此当需要高精度计算大数的时候,该怎样处理呢?(不利用大数类)

现目前我有三条思路

  1. 模拟传统的人工乘法
  2. 竖式优化的乘法
  3. 分而治之
  4. 利用BigInteger类

1. 传统的人工乘法

思路:将乘数的每一位与被乘数相乘,得到的结果后面追加适当的0元素,再将所有的结果相加即可

此思路要用到额外的两个方法

  1. 将两个大数相加
  2. 一位数乘以多位数(包含一位数的情况)

代码如下:

/** 415. 字符串相加 */
public String addStrings(String num1, String num2) {
    int len1 = num1.length(), len2 = num2.length(), temp = 0;
    int max = Math.max(len1, len2);
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < max; ++ i) {
        temp += i < len1 ? num1.charAt(len1 - 1 - i) - '0' : 0;
        temp += i < len2 ? num2.charAt(len2 - 1 - i) - '0': 0;
        stringBuilder.append(temp % 10);
        temp /= 10;
    }
    if(temp != 0) stringBuilder.append(temp);
    return stringBuilder.reverse().toString();
}

/** 43. 字符串相乘 */
public String multiply(String num1, String num2) {
    if("0".equals(num1) || "0".equals(num2))  return "0";
    int len2 = num2.length();
    String string = "";
    for (int i = 0; i < len2; ++ i) {
        // 追加i个0
        StringBuilder stringBuilder = new StringBuilder();
        for (int j = 0; j < i; j++) {
            stringBuilder.append(0);
        }
        string = addStrings(string, mul(num2.charAt(len2 - 1 - i), num1) + stringBuilder);
    }
    return string;
}

/** 一位数乘以多位数 */
public String mul(char ch, String string) {
    int len = string.length();
    int num = ch - 48, carry = 0;
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < len; i++) {
        carry += num * (int)(string.charAt(len - 1 - i) - '0');
        stringBuilder.append(carry % 10);
        carry /= 10;
    }
    if(carry != 0) stringBuilder.append(carry);
    return stringBuilder.reverse().toString();
}

2. 利用竖式优化

注意两个点:

  1. 一个长度为n的和一个长度为m的数相乘,其结果的长度最多为n+m(不信你试试)
  2. num1[i]和num2[j]相乘一定不超过两位数。第一位位于arr[i + j] 第二位位于arr[i + j + 1]
public String multiply(String num1, String num2) {
    if("0".equals(num1) || "0".equals(num2)) return "0";
    int len1 = num1.length(), len2 = num2.length(), temp;
    int[] arr = new int[len1 + len2];
    for (int i = len1 - 1; i >= 0; -- i) {
        int n1 = num1.charAt(i) - 48;
        for (int j = num2.length() - 1; j >= 0; -- j) {
            int n2 = num2.charAt(j) - 48;
            temp = arr[i + j + 1] + n1 * n2;
            arr[i + j + 1] = temp % 10;
            arr[i + j] += temp / 10;
        }
    }
    StringBuilder stringBuilder = new StringBuilder();
    int i = arr[0] == 0 ? 1 : 0;
    while (i < arr.length) {
        stringBuilder.append(arr[i ++]);
    }
    return stringBuilder.toString();
}

3. 分而治之

算法思路:

代码实现:

/** 44. 分治算法 */
public String multiply2(String num1, String num2) {
    if(num1.length() == 1 || num2.length() == 1) return String.valueOf(Integer.valueOf(num1) * Integer.valueOf(num2));
    // 拆分的长度
    int middle = Math.max(num1.length(), num2.length()) / 2;
    // 拆分出a b c d
    String a = num1.substring(0, num1.length() - middle);
    String b = num1.substring(num1.length() - middle);
    String c = num2.substring(0, num2.length() - middle);
    String d = num2.substring(num2.length() - middle);
    // 计算a * c,b * d,和b * c + a * d
    String ac = multiply2(a, c);
    String bd = multiply2(b, d);
    // b * c + a * d = (a + b) * (c + d) - a * c - b * d
    String bcad = subStract(subStract(multiply2(addStrings(a, b), addStrings(c, d)), ac), bd);
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < 2 * middle; ++ i) {
        stringBuilder.append('0');
    }
    return addStrings(bd, addStrings(ac + stringBuilder.toString(), bcad + stringBuilder.substring(middle)));
}


/** 415. 字符串相加 */
public String addStrings(String num1, String num2) {
    int len1 = num1.length(), len2 = num2.length(), temp = 0;
    int max = Math.max(len1, len2);
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < max; ++ i) {
        temp += i < len1 ? num1.charAt(len1 - 1 - i) - '0' : 0;
        temp += i < len2 ? num2.charAt(len2 - 1 - i) - '0': 0;
        stringBuilder.append(temp % 10);
        temp /= 10;
    }
    if(temp != 0) stringBuilder.append(temp);
    return stringBuilder.reverse().toString();
}


/** 字符串的减法 */
public String subStract(String string1, String string2) {
    int len1 = string1.length(), len2 = string2.length(), judge;
    if(len1 > len2) {
        judge = 1;
    }else if (len1 < len2) {
        judge = -1;
    }else {
        judge = string1.compareTo(string2);
    }
    if(judge < 0)  return "-" + subStract(string2, string1);
    else if (judge == 0) return "0";
    int temp = 0;
    int max = Math.max(len1, len2);
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < max; i++) {
        int a = i < len1 ? string1.charAt(len1 - 1 - i) - '0' : 0;
        int b = i < len2 ? string2.charAt(len2 - 1 - i) - '0' : 0;
        int num = a - temp - b;
        if(num < 0) {
            num = 10 + a - b - temp;
            temp = 1;
        }else {
            temp = 0;
        }
        stringBuilder.append(num);
    }
    // 去掉多余的0
    for (int i = stringBuilder.length() - 1; i >= 0; -- i) {
        if(stringBuilder.charAt(i) != '0') {
            break;
        }
        stringBuilder.deleteCharAt(i);
    }
    return stringBuilder.reverse().toString();
}

4. 用BigInteger类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值