高精度除法
高精度除法
给定两个非负整数(不含前导 0)A,B,请你计算 A/B 的商和余数。
所用方法和基本原理
- 数据预处理:
- 首先获取两个字符串A和b的长度ALen和bLen。
- 创建一个数组divA来存储A的每一位数字,从字符串A的末尾开始遍历,将每个字符转换为数字存入数组。
- 将字符串b转换为一个整数divb。通过遍历字符串b,利用Math.pow(10, j) * (b.charAt(i) - '0')这种方式,将每一位数字乘以对应的权值并累加,从而得到b对应的整数值。 - 模拟除法运算:
- 定义一个长度为ALen + 1的结果数组res用于存储商。
- 初始化一个变量t表示余数,初始值为 0。
- 从A的高位开始遍历divA数组。对于每一位,先将当前余数t乘以 10 再加上当前位的数字,得到tmp。然后计算tmp除以divb的结果作为当前位的商存入res数组,同时更新余数t为tmp除以divb的余数。 - 结果处理:
- 计算结束后,t即为最终的余数remainder。
- 从res数组的高位开始跳过前导 0,找到第一个非零元素的位置startIdx。
- 将从startIdx开始到数组开头的元素依次添加到StringBuffer中,得到商的字符串表示。
- 最后返回一个包含商和余数的字符串数组。
代码及注释
public class BigNumberDivision {
// 实现两个非负整数字符串的除法,返回商和余数
public static String[] div(String A, String b) {
// 计算字符串A和b的长度
int ALen = A.length();
int bLen = b.length();
// 创建数组divA用于存储字符串A按位拆分后的数字
int[] divA = new int[ALen];
// 将字符串b转换为整数divb
int divb = 0;
// 将字符串A按位拆分并存入divA数组
for (int i = ALen - 1, j = 0; i >= 0; i--, j++) {
divA[j] = A.charAt(i) - '0';
}
// 将字符串b转换为整数
for (int i = bLen - 1, j = 0; i >= 0; i--, j++) {
divb += Math.pow(10, j) * (b.charAt(i) - '0');
}
// 定义结果数组res用于存储商
int[] res = new int[ALen + 1];
// 定义变量t表示余数,初始值为0
int t = 0;
// 模拟除法运算
for (int i = ALen - 1; i >= 0; i--) {
// 计算当前位的临时值
int tmp = t * 10 + divA[i];
// 计算当前位的商
res[i] = tmp / divb;
// 更新余数
t = tmp % divb;
}
// 最终的余数
int remainder = t;
// 去除商的前导0
int startIdx = ALen;
while (res[startIdx] == 0) {
startIdx--;
if (startIdx < 0) {
// 如果商全为0,直接返回["0", 余数]
return new String[]{"0", String.valueOf(remainder)};
}
}
// 创建StringBuffer用于构建商的字符串
StringBuffer resStr = new StringBuffer();
// 将商的有效位添加到StringBuffer中
for (int i = startIdx; i >= 0; i--) {
resStr.append(res[i]);
}
// 返回包含商和余数的字符串数组
return new String[]{resStr.toString(), String.valueOf(remainder)};
}
}
举例说明
假设 A = "123",b = "4"。
- 数据预处理:
-ALen = 3,bLen = 1。
-divA = [3, 2, 1]。
-divb = 4。 - 模拟除法运算:
- 第一次循环:i = 2,tmp = 0 * 10 + 1 = 1,res[2] = 1 / 4 = 0,t = 1 % 4 = 1。
- 第二次循环:i = 1,tmp = 1 * 10 + 2 = 12,res[1] = 12 / 4 = 3,t = 12 % 4 = 0。
- 第三次循环:i = 0,tmp = 0 * 10 + 3 = 3,res[0] = 3 / 4 = 0,t = 3 % 4 = 3。此时res = [0, 3, 0],remainder = 3。 - 结果处理:
- 跳过前导 0,startIdx = 1。
- 将res[1]和res[0]依次添加到resStr得到"30"。
- 最终返回["30", "3"],即商为 30,余数为 3。
方法的优劣
- 时间复杂度:
- 预处理部分,将A拆分为数组的时间复杂度为 (O(m)),其中m是A的长度;将b转换为整数的时间复杂度为 (O(n)),其中n是b的长度。模拟除法运算部分,时间复杂度为 (O(m))。总体时间复杂度为 (O(m + n)),假设 (m \geq n)。 - 空间复杂度:
- 创建了长度为ALen + 1的数组res和长度为ALen的数组divA,空间复杂度主要由这两个数组决定,为 (O(m)),其中m是A的长度。同时在计算divb时,可能涉及与n相关的临时空间,但总体空间复杂度为 (O(m))。
优点:
- 实现思路较为直观,模拟了手工除法的过程,代码逻辑相对清晰,容易理解和实现。
- 能够处理较大整数的除法运算,不受编程语言内置整数类型范围的限制。
缺点:
- 当 b 是一个非常大的数时,将其转换为整数可能会导致整数溢出,限制了处理大数的能力。
- 空间复杂度较高,需要额外的数组来存储中间结果,对于非常大的数,内存消耗较大。
- 对于大规模数据,该算法的时间复杂度不是最优的,存在更高效的大数除法算法。

浙公网安备 33010602011771号