两个大数相加

听说这是个频繁出现的算法题,在某某网站是的排行很靠前。
在找工作之前,同事提过一次,我没当回事,恰恰在我第一家面试时就碰到了。

两个大数相加。
1、是整数;
2、两个数无限大,long都装不下;
3、不能用BigInteger;
4、不能用任何包装类提供的运算方法;
5、两个数都是以字符串的方式提供。

两个字符串的数字,怎么相加?
其实也简单,核心点考的是ASCII码和相加进位的问题。

比喻字符类型的'9'怎么转换成int的9?
'9' - '0' = 9。这个算法能理解吗?
char类型进行算数运算时是不是自动转换为int类型的了?
字符9的ASCII值是不是比字符0的多9个?这是第一个关键点。
第二个关键点是,注意相加时的进位。

对两个字符串的数字,可以使用字符数组的方式处理,也可以用StringBuffer。
有人会问,StringBuffer每次append都是在后面追加,但是处理数字进位时需要在前面处理。
其实StringBuffer有个方法reverse(),翻转字符串

举个例子比喻下整个处理过程:
String str1 = "123459";
string str2 = "123";
两个字符串需要翻转,为什么?
因为相加处理是从最右边的个位开始的,还有进位处理。
调用reverse()方法处理后:
String str1 = "954321";
string str2 = "321";
现在就好办了,个位对齐了。可以开始相加了,注意进位。
int carry = 0;
计算个位:
int value = str1.charAt(0) + str2.charAt(0) - 2*'0' + carry;
上面这行代码能理解吗?
翻译过来就是:'9' + '3' - 2*'0' + carry;
为什么 - 2*'0' ?
字符进行算术运算时,会转换成ASCII值在进行运算。
故继续翻译为:57 + 51 - 2*48 + 0;
是不是等于 9 + 3 + 0 ?
好,不多废话了。相加后的值为12。
直接把12存储在个位上吗?当然不是,把进位的10部分存储到carry变量中,便于进行十位数字相加时使用:
carry = 12 / 10;
value = 12 % 10;
然后把value的值保存到最终的个位上。

一次上述步骤。

最后需要注意的是,输入的两个字符串数字长度不一定相等。
第一次循环时要以较短的字符串未结束点,计算两个数字和carry的相加和进位。
然后在基于较长的字符串长出的部分循环,与carry相加,处理进位。

public static void main(String[] args) {
	String str1 = "123459";
	String str2 = "123";
	System.out.println(add(str1, str2));//123582
}
 
private static String add(String str1, String str2) {
	//任何一个字符串为null或空字符串,都不需要相加了
	if (str1 == null || "".equals(str1)) {
		return str2;
	}
	if (str2 == null || "".equals(str2)) {
		return str1;
	}
	int maxLength = Math.max(str1.length(), str2.length());
	//定义一个存贮结果的字符串,长度要比最大长度字符串还长一位,用于存储可能出现的进位
	StringBuffer result = new StringBuffer(maxLength + 1);
 
	//翻转两个字符串
	str1 = new StringBuffer(str1).reverse().toString();
	str2 = new StringBuffer(str2).reverse().toString();
 
	//反转后的结果分别为:
	//954321
	//321
	int minLength = Math.min(str1.length(), str2.length());
	//进位
	int carry = 0;
	//当前位上的数值
	int currentNum = 0;
	//循环变量
	int i = 0;
	for (; i < minLength; i++) {
		//分别获取两个字符对应的字面数值,然后相加,再加上进位
		currentNum = str1.charAt(i) + str2.charAt(i) - 2 * '0' + carry;
		//获取进位
		carry = currentNum / 10;
		//处理当前位的最终值
		currentNum %= 10;
		//保存当前位的值到最终的字符缓冲区中
		result.append(String.valueOf(currentNum));
	}
	if (str1.length() < str2.length()) {
		//选择
		str1 = str2;
	}
	for (; i < str1.length(); i++) {
		//分别获取两个字符对应的字面数值,然后相加,再加上进位
		currentNum = str1.charAt(i) - '0' + carry;
		//获取进位
		carry = currentNum / 10;
		//处理当前位的最终值
		currentNum %= 10;
		//保存当前位的值到最终的字符缓冲区中
		result.append(String.valueOf(currentNum));
	}
	//处理最后一个的进位(当循环结束后,是不是还可能会有一个进位)
	if (carry > 0) {
		result.append(String.valueOf(carry));
	}
	//最后翻转恢复字符串,再返回
	return result.reverse().toString();
}