用字符串或者数组表示大数是一种很简单有效的表示方式。在打印1到最大的n为数的问题上采用的是使用数组表示大数的方式。在相关题实现任意两个整数的加法、减法、乘法的实现中,采用字符串对大数进行表示,不过在具体的计算中,还是要将字符串转化成字符数组来进行计算。
实现两个大数的加法,要考虑到两个问题,两个数的和的位数问题,以及如何处理两个数按位相加产生的进位问题。首先两个整数相加,两个数的和的位数最多比最大的整数的位数多1;这样和的位数就确定了。对于进位问题,我的做法是先进行按位相加,相加操作完成后再按照数位来判断是否需要进位,这样只需要遍历一下数组对于需要进位的为向高位进位就可以了。在计算两个数的加法的时候是要低位对其然后相加的,用字符串转化成的字符数组表示数字,数组的索引数字大的表示的是数字的低位,这样在计算过程中为了方便从数组的低索引开始算可以将字符串翻转,这样就很容易进行按位计算了。
1 package Solution; 2 3 /** 4 * 剑指offer面试题12相关题目:大位数加减乘法的实现、 5 * 解题思路:使用字符串表示数字,转换成数组进行计算。按位相加,然后处理进位 6 * 把字符串翻转过来模拟从低位到高位的相加 7 * @author GL 8 * 9 */ 10 public class No12BigDigitalCalculate { 11 12 /** 13 * 两个大数相加,默认两个大数位不带符号位的正数 14 * @param a 15 * @param b 16 * @return 17 */ 18 public static String bigDigitalSum(String a,String b){ 19 20 //翻转两个字符串并转换成数组 21 char[] aArray=new StringBuffer(a).reverse().toString().toCharArray(); 22 char[] bArray=new StringBuffer(b).reverse().toString().toCharArray(); 23 int aLength=aArray.length; 24 int bLength=bArray.length; 25 26 //两个整数相加的最大位数为两个整数中最大位数+1 27 int maxLength=aLength>bLength?aLength:bLength; 28 int[] result=new int[maxLength+1]; 29 30 //按照数位对应相加 31 for(int i=0;i<maxLength+1;i++){ 32 //判断当前位是否超过了当前数值的最大位数,如果是用0代替进行运算 33 int aInt=i<aLength?(aArray[i]-'0'):0; 34 int bInt=i<bLength?(bArray[i]-'0'):0; 35 result[i]=aInt+bInt; 36 } 37 38 //处理进位,进位加到相邻的高位上 39 for(int i=0;i<result.length;i++){ 40 if(result[i]>10){ 41 result[i+1]=result[i+1]+result[i]/10; 42 result[i]=result[i]%10; 43 } 44 } 45 46 StringBuffer realResult=new StringBuffer(); 47 //判断是否有前置0,如果有不会打印出来 48 boolean isBeginning=true; 49 for(int i=result.length-1;i>=0;i--){ 50 if(result[i]==0&&isBeginning) 51 continue; 52 else 53 isBeginning=false; 54 //从后向前将结果逆转 55 realResult.append(result[i]); 56 } 57 return realResult.toString(); 58 } 59 60 public static void main(String[] args) { 61 String a="88900988"; 62 String b="7878778888"; 63 System.out.println(bigDigitalSum(a,b)); 64 65 } 66 }
实现两个大数相减和实现两个大数相加的思路相近,首先要判断两个数相减的差的位数问题。两个数的差的位数应该不多于最大的整数的位数(此处指两个正整数)。然后要考虑两个整数相减的差的符号问题,如果被减数的位数少于减数的位数,那么得到的差值应该是负号。然后考虑按位相减产生的借位问题的处理方式,同按位相加的进位一样,先让各个数位相减,然后统一处理借位问题。
1 package Solution; 2 3 /** 4 * 剑指offer面试题12相关题目:大位数加减乘法的实现、 5 * 解题思路:使用字符串表示数字,转换成数组进行计算。按位相加,然后处理进位 6 * 把字符串翻转过来模拟从低位到高位的相加 7 * @author GL 8 * 9 */ 10 public class No12BigDigitalCalculate { 11 12 /** 13 * 两个大数相减,默认没有符号位,且都为正数 14 * @param a 15 * @param b 16 * @return 17 */ 18 public static String bigDigitalSub(String a,String b){ 19 //翻转字符串并转化成数组 20 char[] aArray=new StringBuilder(a).reverse().toString().toCharArray(); 21 char[] bArray=new StringBuilder(b).reverse().toString().toCharArray(); 22 int aLength=aArray.length; 23 int bLength=bArray.length; 24 //找到最大的位数,两个整数的差的位数小于等于两个整数中的最大位数 25 int maxLength=aLength>bLength?aLength:bLength; 26 int[] result=new int[maxLength]; 27 //判断结果符号 28 char sign='+'; 29 if(aLength<bLength) 30 sign='-'; 31 else if(aLength==bLength){ 32 int i=maxLength-1; 33 while(i>0&&aArray[i]==bArray[i]) 34 i--; 35 if(aArray[i]<bArray[i]) 36 sign='-'; 37 } 38 //开始计算结果集 39 for(int i=0;i<maxLength;i++){ 40 int aInt=i<aLength?aArray[i]-'0':0; 41 int bInt=i<bLength?bArray[i]-'0':0; 42 if(sign=='-') 43 result[i]=bInt-aInt; 44 else 45 result[i]=aInt-bInt; 46 } 47 //处理结果集,如果结果集中的某一位小于0,则向高位借位,然后将本位加10 48 for(int i=0;i<maxLength-1;i++){ 49 if(result[i]<0){ 50 result[i+1]-=1; 51 result[i]+=10; 52 } 53 } 54 55 //处理结果集,转化成真正结果 56 StringBuffer realResult=new StringBuffer(); 57 if(sign=='-') 58 realResult.append('-'); 59 boolean isBeginning=true; 60 for(int i=maxLength-1;i>=0;i--){ 61 if(result[i]==0&&isBeginning){ 62 continue; 63 } 64 else 65 isBeginning=false; 66 realResult.append(result[i]); 67 } 68 if(realResult.toString().equals("")) 69 realResult.append('0'); 70 return realResult.toString(); 71 } 72 73 public static void main(String[] args) { 74 String a="88900988"; 75 String b="7878778888"; 76 System.out.println(bigDigitalSub(a,b)); 77 } 78 }
实现两个大数的乘法,两个整数的乘积的位数最多为两个整数的位数的和,两个整数相乘的计算方式的规律是,被乘数的第i位和乘数的第j位进行乘法运算的结果是算在乘积的第i+j位上的,比如两个整数的各位相乘,结果应该在乘积的个位上(暂时不考虑进位),个位和十位相乘得结果在积的十位上,这样就可以像加减法一样,按照数位算出两个数相乘,各个数位的值,然后再集中处理进位的问题。
1 package Solution; 2 3 /** 4 * 剑指offer面试题12相关题目:大位数加减乘法的实现、 5 * 解题思路:使用字符串表示数字,转换成数组进行计算。按位相加,然后处理进位 6 * 把字符串翻转过来模拟从低位到高位的相加 7 * @author GL 8 * 9 */ 10 public class No12BigDigitalCalculate { 11 12 /** 13 * 两个大数相乘 14 * @param a 15 * @param b 16 * @return 17 */ 18 public static String bigDigitalMultiply(String a,String b){ 19 //判断两字符串是否带有符号位,以及计算乘积的符号位 20 char signA=a.charAt(0); 21 char signB=b.charAt(0); 22 char sign='+'; 23 if(signA=='+'||signA=='-'){ 24 sign=signA; 25 a=a.substring(1); 26 } 27 if(signB=='+'||signB=='-'){ 28 if(sign==-signB) 29 sign='+'; 30 else 31 sign='-'; 32 b=b.substring(1); 33 } 34 //将大数翻转,并转化为数组 35 char[] aArray=new StringBuffer(a).reverse().toString().toCharArray(); 36 char[] bArray=new StringBuffer(b).reverse().toString().toCharArray(); 37 int aLength=aArray.length; 38 int bLength=bArray.length; 39 int length=aLength+bLength; 40 int[] result=new int[length]; 41 //计算结果集合 42 for(int i=0;i<aLength;i++){ 43 for(int j=0;j<bLength;j++){ 44 result[i+j]=result[i+j]+(aArray[i]-'0')*(bArray[j]-'0'); 45 } 46 } 47 //处理结果集合,如果大于10的则向高位产生进位 48 for(int i=0;i<length-1;i++){ 49 if(result[i]>10){ 50 result[i+1]+=result[i]/10; 51 result[i]%=10; 52 } 53 54 } 55 //把结果转化为正常序列 56 StringBuffer sb=new StringBuffer(); 57 if(sign=='-') 58 sb.append('-'); 59 boolean flag=true; 60 for(int i=length-1;i>=0;i--){ 61 if(result[i]==0&&flag) 62 continue; 63 else 64 flag=false; 65 sb.append(result[i]); 66 } 67 if(sb.toString()=="") 68 sb.append('0'); 69 return sb.toString(); 70 } 71 72 73 public static void main(String[] args) { 74 String a="88900988"; 75 String b="7878778888"; 76 System.out.println(bigDigitalMultiply(a,b)); 77 78 } 79 }
在两个大数相乘的实现中考虑到了输入的数组中带有符号的问题,而在两位数加减的实现中只是实现了最基本的两个整数的加减,而且在三个实现中都没有对字符串所表示的数字进行有效性检验,在实现任意两个带符号的加减法中,可先判断字符串的有效性,然后检查是否带符号,最后调用无符号加法和无符号减法来取得结果,比如两个负数相减可以求得两个正数的和然后加负号,一个正数与一个负数相加可以采用两个无符号数相减来实现。