一.题目描述
给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。
提示:
num1 和num2 的长度都小于 5100
num1 和num2 都只包含数字 0-9
num1 和num2 都不包含任何前导零
你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式
二.题目解析
public static String addStrings(String num1, String num2) {
/*双指针法*/
int i = num1.length() - 1;
int j = num2.length() - 1;
//cur表示当前位的相加之和,add表示当前位产生的进位
int add = 0,cur = 0,number1,number2;
StringBuilder stringBuilder = new StringBuilder("");
//从最后一位开始计算
while (i >= 0 && j >= 0){
//ASCII 码相减,得到字符对应的 int 数值
number1 = num1.charAt(i) - '0';
number2 = num2.charAt(j) - '0';
cur = number1 + number2 + add;
add = cur / 10;
cur = cur % 10;
stringBuilder.append(cur);
//向前遍历
i--;
j--;
}
//两个字符串长度不相等,短的先遍历完,剩下的只需要在长的剩余部分计算
while (i >= 0){
cur = num1.charAt(i) - '0' + add;
add = cur / 10;
cur = cur % 10;
stringBuilder.append(cur);
i--;
}
while (j >= 0){
cur = num2.charAt(j) - '0' + add;
add = cur / 10;
cur = cur % 10;
stringBuilder.append(cur);
j--;
}
2.1中的代码冗余在对两个字符串长度的判断,和遍历完成时头部是否添加进位1的判断
代码还可以进一步优化:
public String addStrings1(String num1, String num2) {
/*双指针法,第一个方法的精简版
* 时间复杂度 O(max(M,N)),取较长字符串的长度
* 空间复杂度O(1):指针与变量使用常数大小空间
* */
StringBuilder res = new StringBuilder("");
int i = num1.length() - 1, j = num2.length() - 1, carry = 0;
//while循环也兼容两个字符串都遍历完产生进位的情形
while(i >= 0 || j >= 0 || carry != 0){
//长度较短的字符串溢出索引位置填充为0,便于计算
int n1 = i >= 0 ? num1.charAt(i) - '0' : 0;
int n2 = j >= 0 ? num2.charAt(j) - '0' : 0;
int tmp = n1 + n2 + carry;
carry = tmp / 10;
res.append(tmp % 10);
i--; j--;
}
return res.reverse().toString();
}
3.考虑到栈的先进后出特性,我们还可以利用栈来依次保存,以实现“翻转”的效果
public String addStrings2(String num1, String num2) {
/*双指针法,利用栈翻转*/
StringBuilder res = new StringBuilder("");
Stack<Integer> stack = new Stack<>();
int i = num1.length() - 1, j = num2.length() - 1, carry = 0;
while(i >= 0 || j >= 0 || carry != 0){
int n1 = i >= 0 ? num1.charAt(i) - '0' : 0;
int n2 = j >= 0 ? num2.charAt(j) - '0' : 0;
int tmp = n1 + n2 + carry;
carry = tmp / 10;
stack.push(tmp % 10);
i--; j--;
}
while (!stack.isEmpty()){
res.append(stack.pop());
}
return res.toString();
}
拓展:36进制加法
题目描述
36进制由0-9,a-z,共36个字符表示。
要求按照加法规则计算出任意两个36进制正整数的和,如1b + 2x = 48 (解释:47+105=152)
要求:不允许使用先将36进制数字整体转为10进制,相加后再转回为36进制的做法
思路:采用方式2(把10进制改成36进制即可):
/**
leetcode415拓展
36进制加法
*/
public class Solution8 {
public String addBase36Strings(String num1, String num2) {
/*双指针法,第一个方法的精简版
* 时间复杂度 O(max(M,N)),取较长字符串的长度
* 空间复杂度O(1):指针与变量使用常数大小空间
* */
StringBuilder res = new StringBuilder("");
int i = num1.length() - 1, j = num2.length() - 1, carry = 0;
//while循环也兼容两个字符串都遍历完产生进位的情形
while(i >= 0 || j >= 0 || carry != 0){
//长度较短的字符串溢出索引位置填充为0,便于计算
int n1 = i >= 0 ? getBase36Int(num1.charAt(i)) : 0;
int n2 = j >= 0 ? getBase36Int(num2.charAt(j)) : 0;
int tmp = n1 + n2 + carry;
carry = tmp / 36;
//该位上计算得到的数字转为36进制字符
res.append(getBase36Char(tmp % 36));
i--; j--;
}
return res.reverse().toString();
}
char getBase36Char(int n){
/*36进制数字转字符类型*/
if(n <= 9){
return (char)(n + '0');
}
return (char)(n - 10 + 'a');
}
int getBase36Int(char ch){
/*36进制字符转数字*/
if(ch <= '9'){
return ch - '0';
}
return ch - 'a' + 10;
}
public static void main(String[] args) {
Solution8 s8 = new Solution8();
System.out.println(s8.addBase36Strings("1c","zi"));
System.out.println(s8.addBase36Strings("mz7","gw"));
}
}
运行: