大整数乘法---分治
来源:互联网 发布:姆潘巴现象知乎 编辑:程序博客网 时间:2024/06/07 04:45
分治法:
1 将问题的实例划分成同一个问题的较小的实例,最好拥有同样的规模
2 对这些较小的实例求解(一般使用递归方法,但在问题规模足够小的时候,可能会利用另一个算法)
3 如果必要的话,合并这些较小问题的解,以得到原问题的解。
自己理解看来,首先分治法重点的步骤在于合并,因为小问题求解肯定是很简单的,重点步骤在于合并小问题得到原问题的解。
大整数问题
计算公式:
a = a0a1; b = b0b1
c = a x b = c2*10^2 + c1*10 + c0
其中c1可以转化为c1 = (a1 + a0) * (b1 + b0 ) - (c2 + c0)
但是我就算知道计算公式,知道分治思想,还是写不出代码来,下面是别人的代码,必须承认写这个算法的人是个大牛:
public class BigIntMultiply{ //规模只要在这个范围内就可以直接计算了 private final static int SIZE = 4; // 此方法要保证入参len为X、Y的长度最大值 private static String bigIntMultiply(String X, String Y, int len) { // 最终返回结果 String str = ""; // 补齐X、Y,使之长度相同 X = formatNumber(X, len); Y = formatNumber(Y, len); // 少于4位数,可直接计算 if (len <= SIZE) { return "" + (Integer.parseInt(X) * Integer.parseInt(Y)); } // 将X、Y分别对半分成两部分 int len1 = len / 2; int len2 = len - len1; String A = X.substring(0, len1); String B = X.substring(len1); String C = Y.substring(0, len1); String D = Y.substring(len1); // 乘法法则,分块处理 int lenM = Math.max(len1, len2); String AC = bigIntMultiply(A, C, len1); String AD = bigIntMultiply(A, D, lenM); String BC = bigIntMultiply(B, C, lenM); String BD = bigIntMultiply(B, D, len2); // 处理BD,得到原位及进位 String[] sBD = dealString(BD, len2); // 处理AD+BC的和 String ADBC = addition(AD, BC); // 加上BD的进位 if (!"0".equals(sBD[1])) { ADBC = addition(ADBC, sBD[1]); } // 得到ADBC的进位 String[] sADBC = dealString(ADBC, lenM); // AC加上ADBC的进位 AC = addition(AC, sADBC[1]); // 最终结果 str = AC + sADBC[0] + sBD[0]; return str; } // 两个数字串按位加 private static String addition(String ad, String bc) { // 返回的结果 String str = ""; // 两字符串长度要相同 int lenM = Math.max(ad.length(), bc.length()); ad = formatNumber(ad, lenM); bc = formatNumber(bc, lenM); // 按位加,进位存储在temp中 int flag = 0; // 从后往前按位求和 for (int i = lenM - 1; i >= 0; i--) { int t = flag + Integer.parseInt(ad.substring(i, i + 1)) + Integer.parseInt(bc.substring(i, i + 1)); // 如果结果超过9,则进位当前位只保留个位数 if (t > 9) { flag = 1; t = t - 10; } else { flag = 0; } // 拼接结果字符串 str = "" + t + str; } if (flag != 0) { str = "" + flag + str; } return str; } // 处理数字串,分离出进位; // String数组第一个为原位数字,第二个为进位 private static String[] dealString(String ac, int len1) { String[] str = {ac, "0"}; if (len1 < ac.length()) { int t = ac.length() - len1; str[0] = ac.substring(t); str[1] = ac.substring(0, t); } else { // 要保证结果的length与入参的len一致,少于则高位补0 String result = str[0]; for (int i = result.length(); i < len1; i++) { result = "0" + result; } str[0] = result; } return str; } // 乘数、被乘数位数对齐 private static String formatNumber(String x, int len) { while (len > x.length()) { x = "0" + x; } return x; } //测试桩 public static void main(String[] args) { // 正则表达式:不以0开头的数字串 String pat = "^[1-9]\\d*$"; Pattern p = Pattern.compile(pat); // 获得乘数A System.out.println("请输入乘数A(不以0开头的正整数):"); Scanner sc = new Scanner(System.in); String A = sc.nextLine(); Matcher m = p.matcher(A); if (!m.matches()) { System.out.println("数字不合法!"); return; } // 获得乘数B System.out.println("请输入乘数B(不以0开头的正整数):"); sc = new Scanner(System.in); String B = sc.nextLine(); m = p.matcher(B); if (!m.matches()) { System.out.println("数字不合法!"); return; } System.out.println(A + " * " + B + " = " + bigIntMultiply(A, B, Math.max(A.length(), B.length()))); }}
总结来说,当自己动手写大整数相乘时,大概步骤我还是知道怎么写的,但是数位相加和将数位分离这两个函数是我没有想到的。
通过数位分离将树分离成了进位,那么可以将字符串合并。
但是这个算法有一个美中不足的地方,就是使用了4次相乘,最后的时间复杂度为M(n) = 4 ^ log 2 n = n^2
如果使用c1的计算公式,那么算法的4次乘法就可以转化为3次乘法,那么时间复杂度就可以转为为n^1.585,这就是我要完成的任务了~
0 0
- 大整数分治乘法
- 大整数乘法---分治
- 大整数乘法-分治
- 分治-大整数乘法
- 大整数乘法(分治法)
- 分治算法-大整数乘法
- 大整数乘法 ------分治法
- 分治算法--大整数乘法
- 递归分治-大整数乘法
- 【分治算法】大整数乘法
- 分治法大整数乘法和普通大整数乘法
- 分治法解决大整数乘法问题
- 分治法 --- 大整数的乘法
- 大整数的乘法(分治法)
- 分治法实现大整数乘法
- 分治法实现大整数乘法
- 算法学习-分治法-大整数乘法
- 分治法 --- 大整数的乘法
- DOCTYPE
- win0 环境下局域网 搭建FTP服务器
- 编程中遇到的Bugs
- DML、DDL、DCL
- [LeetCode-111] Minimum Depth of Binary Tree (二叉树最小深度)
- 大整数乘法---分治
- MySQL慢日志查询用法
- 深入理解Java内存模型(六)——final
- Python学习手册 - 11
- 16 复杂链表的复制
- 从僵尸网络追踪到入侵检测 第8章 Honeyd配置文件使用
- 二叉树三种遍历(递归及非递归)的实现
- 修改mysql数据库的用户名和密码
- 安装完 MySQL 后必须调整的 10 项配置