原创公众号:bigsai
原创不易,如果有收获请不要吝啬你的一键三连!
大家好,我是bigsai!最近,大数加减频频登上笔试的舞台,小伙伴们在群里也分享自己遇到面试官碰到大数运算的题目,想着这么重要而简单的知识点我还没写过,那得好好和大家一起总结一下。
各位有过分类刷题的小伙伴,可能看到很多人分类 字符串、贪心、动态规划、bfs、dfs、大数、数论等,初听大数,你可能会差异:大数是个啥?听起来怪高大上的。
大数,其实就是很大很大数字(可能远超32、64位,基础类型无法表示)的加减法,在Java中我们可以使用一个大数类(BigInteger等)很容易解决大数的各种运算,但如果遇到面试官他肯定会让你手写的。
这个数字一般用字符串、链表等形式表示、返回,大数运算的核心就是:模拟,模拟我们日常用纸笔算数字的加减乘除流程,然后再根据计算机、编程语言等特性适当存储计算即可,不过,大数除法运算稍微特殊一点,和我们直接模拟的思维方式稍有不同。
大数加法大数加法是最简单的,简单模拟即可。首先,我们想一下两个数加法的流程:从右向左计算求和、进位,一直到最后。
在编程语言中同样也是模拟从右向左逐位相加的过程,不过在具体实现上需要注意一些细节。
1、枚举字符串将其转换程char[]提高效率
2、从右往左进行计算,可以将结果放到一个数组中最后组成字符串,也可以使用StringBuider拼接,拼接的时候最后要逆置一下顺序。
3、余数每次叠加过需要清零,两数相加如果大于等于10即有余数,添加到结果中该位置的数也应该是该数%10的结果。
4、计算完最后还要看看余数是否为1,如果为1需要将其添加到结果,例如 "991"+"11"算三个位置为002但还有一个余数需要添加,所以应该是1002。
当然在具体实现上方法较多,你可以首先就将字符串逆置然后从前往后就可以计算了。当然我这里实现的是字符串从后向前各个位对应计算,然后将结果顺序添加到StringBuilder上。
这题在力扣【415两数相加】可以检验自己代码,实现代码为:
public String addStrings(String num1, String num2) { // 公众号:bigsai 欢迎你的关注 int len1=num1.length()-1,len2=num2.length()-1; char ch1[]=num1.toCharArray(); char ch2[]=num2.toCharArray(); StringBuilder sb=new StringBuilder(); int remainder =0;//计算余数 while (len1>=0||len2>=0) { int n1=len1>=0?(ch1[len1--]-'0'):0; int n2=len2>=0?(ch2[len2--]-'0'):0; int num=n1+n2+remainder;//求和对应数字 remainder=num/10;//是否进位 sb.append(num%10);// 添加到结果字符串中 } if(remainder>0)//是否还需要进位 { sb.append(remainder); } //反装即为结果 return sb.reverse().toString(); } 大数减法加法对应的就是减法,有了上面大数加法的实现思路,那么我想你在大数减法也应该有点想法,但是减法和加法不同的是减法有位置的区别,加法需要进位而减法需要借位。并且大整正数减法可能产生正负也不一定。
两个正数,如果大数减去小数,那么一切正常,结果是一个正数;但如果小数减去大数,那么结果将是一个负数,并且结果处理起来比较麻烦。 所以在这里全部转成大-小处理(大-小不存在不能借位的情况)。
1、执行计算前首先比较减数(num1)和被减数(num2)的大小,如果num1>num2,那么就模拟num1-num2的过程,如果num1<num2,那么结果就为-(num2-num1) 。当然可以为了稳定模拟时候一个大一个小,可将num1始终指向较大的那个数,少写一个if/else.
2、在比较两个数字大小的时候,因为是字符形式,首先比较两个字符串的长度,长的那个更大短的那个更小,如果两个字符串等大,那么就可以通过字典序从前往后进行比较(Java可直接使用compareTo方法)。
3、和加法不同的是,减法前面可能产生若干前缀0,这些0是需要你去掉的,例如"1100"-"1000"计算得到的结果位"0100",你就要吧前面的0去掉返回"100"。
4、具体实现的时候和加法相似,如果使用StringBuilder存储,需要逆置顺序,如果是个负数,前面还要加上'-'.
5、每个位置正常进行减法运算,如果值小于0,那么就需要向上借位(+10),那么处理上一位进行减法时候还要将借位的处理一下。