两数相加
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
例如:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
题目来源:力扣(LeetCode)
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
初始思路
拿到题目的第一个思路是:通过将链表解析成数字,相加后再转换成链表
于是有了以下代码。。。(错误代码)
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
Long listNodeBack = getListNodeBack(l1);
System.out.println(listNodeBack);
Long listNodeBack1 = getListNodeBack(l2);
System.out.println(listNodeBack1);
Long rtnNum = listNodeBack + listNodeBack1;
System.out.println(rtnNum);
return getListNode(rtnNum);
}
public Long getListNodeBack(ListNode LN){
Long x = Long.valueOf(LN.val);
Long rtn = 10L;
ListNode next = LN;
while ((next = next.next)!=null){
x = x+next.val*rtn;
rtn*=10;
}
return x;
}
public ListNode getListNode(Long num){
ListNode listNodeNext = null;
ListNode rtn = new ListNode(0);
while (num>0){
int i = new Long(num % 10).intValue();
num = (num - i)/10;
ListNode listNode ;
if(listNodeNext == null){
listNode = new ListNode(i);
rtn= listNode;
}else {
listNodeNext.val = i;
listNode = null;
listNode = listNodeNext;
}
if(num>0){
listNode.next = new ListNode();
listNodeNext = null;
listNodeNext = listNode.next;
}
}
return rtn;
}
}
以上代码存在一个致命问题:链表长度无限加长时,long类型也无法支撑
转换思路:将每个节点各自相加
如:9-8-7 和 1-3-1-4-6-3
9+1 、8+3 、7+1 、4、6、3
10-11-8-4-6-3
遇10 进位 ----》 0-2-9-4-6-3
于是又有了下面的代码
BUG修复后(初版 =_= 仍然不完美):
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
// 遍历两个链表对应位相加
// 9-8-7 和 1-3-1-4-6-3
// 9+1 、8+3 、7+1 、4、6、3
// 遍历 两个链表其中一个存在下一节点则继续
ListNode l1Parent = l1;
ListNode l2Parent = l2;
// 相加大于 10表示需要进位 1 否则 0
int carry = 0;
ListNode listNodeNext = null;
ListNode rtn = new ListNode();
while (l1Parent!=null||l2Parent!=null||carry==1){
int l1Val = 0;
int l2Val = 0;
if(l1Parent!=null&&l1Parent.val!=0){
l1Val = l1Parent.val;
}
if(l2Parent!=null&&l2Parent.val!=0){
l2Val = l2Parent.val;
}
int rtnNum = l1Val + l2Val + carry;
if(rtnNum>=10){
rtnNum = rtnNum %10;
carry = 1;
}else {
carry = 0;
}
ListNode listNode ;
if(listNodeNext == null){
listNode = new ListNode(rtnNum);
rtn= listNode;
}else {
listNodeNext.val = rtnNum;
listNode = listNodeNext;
}
// 下一节点还有子节点时 新增链表也要加一个子节点
if((l1Parent!=null&&l1Parent.next!=null)
||(l2Parent!=null&&l2Parent.next!=null)||carry==1){
listNode.next = new ListNode();
listNodeNext = listNode.next;
}
// 转至下一节点
if(l1Parent!=null){
l1Parent = l1Parent.next;
}
if(l2Parent!=null){
l2Parent = l2Parent.next;
}
}
return rtn;
}
此时程序已经可以正常执行,但是耗时较久,在代码层面上再次优化
优化后:
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
// 遍历两个链表对应位相加
// 9-8-7 和 1-3-1-4-6-3
// 9+1 、8+3 、7+1 、4、6、3
// 遍历 两个链表其中一个存在下一节点则继续
// 相加大于 10表示需要进位 1 否则 0
int carry = 0;
ListNode listNodeNext = null;
ListNode rtn = new ListNode();
while (l1!=null||l2!=null){
int l1Val = l1!=null?l1.val:0;
int l2Val = l2!=null?l2.val:0;
int rtnNum = l1Val + l2Val + carry;
carry = rtnNum/10;
if(listNodeNext == null){
rtn = listNodeNext = new ListNode(rtnNum %10);
}else {
listNodeNext.next = new ListNode(rtnNum %10);
listNodeNext = listNodeNext.next;
}
// 转至下一节点
if(l1!=null){
l1 = l1.next;
}
if(l2!=null){
l2 = l2.next;
}
}
if(carry==1){
listNodeNext.next = new ListNode(carry);
}
return rtn;
}
此时程序就比较完美了