|
| 1 | +package com.example; |
| 2 | + |
| 3 | + |
| 4 | +import java.util.ArrayList; |
| 5 | +import java.util.Collections; |
| 6 | + |
| 7 | +public class LeetcodeTest { |
| 8 | + |
| 9 | + public static void main(String[] args) { |
| 10 | +// String a = "1234567891011121314151617181920"; |
| 11 | +// String b = "2019181716151413121110987654321"; |
| 12 | + |
| 13 | +// String a = "999999999999"; |
| 14 | +// String b = "999999999999"; |
| 15 | + |
| 16 | + String a = "24566"; |
| 17 | + String b = "452053"; |
| 18 | + |
| 19 | +// String a = "98"; |
| 20 | +// String b = "21"; |
| 21 | + |
| 22 | + char[] charArr1 = a.trim().toCharArray(); |
| 23 | + char[] charArr2 = b.trim().toCharArray(); |
| 24 | + |
| 25 | + // 字符数组转换为int[]数组 |
| 26 | + int[] arr1 = new int[charArr1.length]; |
| 27 | + int[] arr2 = new int[charArr2.length]; |
| 28 | + for(int i = 0; i < charArr1.length; i++){ |
| 29 | + arr1[i] = charArr1[i] - '0'; |
| 30 | + } |
| 31 | + for(int i = 0; i < charArr2.length; i++){ |
| 32 | + arr2[i] = charArr2[i] - '0'; |
| 33 | + } |
| 34 | + |
| 35 | + // 开始计算 |
| 36 | +// int[] result = LeetcodeTest.bigNumberMultiply2(arr1, arr2); |
| 37 | +// System.out.println(a + " * " + b + " = " + Arrays.toString(result).replace(", ", "")); |
| 38 | + System.out.println(LeetcodeTest.karatsuba(24566 , 452053)); |
| 39 | + } |
| 40 | + |
| 41 | + |
| 42 | + /** |
| 43 | + * 大数相乘 - 模拟乘法手算累加 |
| 44 | + */ |
| 45 | + public static Integer[] bigNumberMultiply(int[] arr1, int[] arr2){ |
| 46 | + ArrayList<Integer> result = new ArrayList<>(); //中间求和的结果 |
| 47 | + |
| 48 | + //arr2 逐位与arr1相乘 |
| 49 | + for(int i = arr2.length - 1; i >= 0; i--){ |
| 50 | + int carry = 0; |
| 51 | + ArrayList<Integer> singleList = new ArrayList<>(); |
| 52 | + |
| 53 | + //arr2 逐位单次乘法的结果 |
| 54 | + for(int j = arr1.length - 1; j >= 0; j--){ |
| 55 | + int r = arr2[i] * arr1[j] + carry; |
| 56 | + int digit = r % 10; |
| 57 | + carry = r / 10; |
| 58 | + |
| 59 | + singleList.add(digit); |
| 60 | + } |
| 61 | + if(carry != 0){ |
| 62 | + singleList.add(carry); |
| 63 | + } |
| 64 | + |
| 65 | + int resultCarry = 0, count = 0; |
| 66 | + int k = 0; |
| 67 | + int l = 0; |
| 68 | + int offset = arr2.length - 1 - i; //加法的偏移位 |
| 69 | + ArrayList<Integer> middleResult = new ArrayList<>(); |
| 70 | + |
| 71 | + //arr2每位乘法的结果与上一轮的求和结果相加,从右向左做加法并进位 |
| 72 | + while (k < singleList.size() || l < result.size()) { |
| 73 | + int kv = 0, lv = 0; |
| 74 | + if (k < singleList.size() && count >= offset) { |
| 75 | + kv = singleList.get(k++); |
| 76 | + } |
| 77 | + if (l < result.size()) { |
| 78 | + lv = result.get(l++); |
| 79 | + } |
| 80 | + int sum = resultCarry + kv + lv; |
| 81 | + middleResult.add(sum % 10); //相加结果从右向左(高位到低位)暂时存储,最后需要逆向输出 |
| 82 | + resultCarry = sum / 10; |
| 83 | + count++; |
| 84 | + } |
| 85 | + if(resultCarry != 0){ |
| 86 | + middleResult.add(resultCarry); |
| 87 | + } |
| 88 | + result.clear(); |
| 89 | + result = middleResult; |
| 90 | + } |
| 91 | + |
| 92 | + Collections.reverse(result); //逆向输出结果 |
| 93 | + return result.toArray(new Integer[result.size()]); |
| 94 | + } |
| 95 | + |
| 96 | + |
| 97 | + /** |
| 98 | + * 大数相乘 - 模拟乘法手算累加 |
| 99 | + */ |
| 100 | + public static int[] bigNumberMultiply2(int[] num1, int[] num2){ |
| 101 | + // 分配一个空间,用来存储运算的结果,num1长的数 * num2长的数,结果不会超过num1+num2长 |
| 102 | + int[] result = new int[num1.length + num2.length]; |
| 103 | + |
| 104 | + // 先不考虑进位问题,根据竖式的乘法运算,num1的第i位与num2的第j位相乘,结果应该存放在结果的第i+j位上 |
| 105 | + for (int i = 0; i < num1.length; i++){ |
| 106 | + for (int j = 0; j < num2.length; j++){ |
| 107 | + result[i + j + 1] += num1[i] * num2[j]; |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + //单独处理进位 |
| 112 | + for(int k = result.length-1; k > 0; k--){ |
| 113 | + if(result[k] > 10){ |
| 114 | + result[k - 1] += result[k] / 10; |
| 115 | + result[k] %= 10; |
| 116 | + } |
| 117 | + } |
| 118 | + return result; |
| 119 | + } |
| 120 | + |
| 121 | + /** |
| 122 | + * Karatsuba乘法 |
| 123 | + */ |
| 124 | + public static long karatsuba(long num1, long num2){ |
| 125 | + if(num1 < 10 || num2 < 10) return num1 * num2; |
| 126 | + |
| 127 | + // 计算拆分长度 |
| 128 | + int size1 = String.valueOf(num1).length(); |
| 129 | + int size2 = String.valueOf(num2).length(); |
| 130 | + int halfN = Math.max(size1, size2) / 2; |
| 131 | + |
| 132 | + /* 拆分为a, b, c, d */ |
| 133 | + long a = Long.valueOf(String.valueOf(num1).substring(0, size1 - halfN)); |
| 134 | + long b = Long.valueOf(String.valueOf(num1).substring(size1 - halfN)); |
| 135 | + long c = Long.valueOf(String.valueOf(num2).substring(0, size2 - halfN)); |
| 136 | + long d = Long.valueOf(String.valueOf(num2).substring(size2 - halfN)); |
| 137 | + |
| 138 | + // 计算z2, z0, z1, 此处的乘法使用递归 |
| 139 | + long z2 = karatsuba(a, c); |
| 140 | + long z0 = karatsuba(b, d); |
| 141 | + long z1 = karatsuba((a + b), (c + d)) - z0 - z2; |
| 142 | + |
| 143 | + return (long)(z2 * Math.pow(10, (2*halfN)) + z1 * Math.pow(10, halfN) + z0); |
| 144 | + } |
| 145 | + |
| 146 | +} |
0 commit comments