题目
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,
并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
我的解答
思路如下:
新创建一个链表,每次相加的结果存放到新的链表中,这里主要的一个问题就是进位。每次相加后都需要进行判断,如果相加的和大于10,则需要进位,存放到新链表中的数据为原链表节点数据相加后的数据再加上上一次进位的结果对10取余。由此可知,相加所得到的sum是l1.val + l2.val + add(这里我用add变量来表示进位),而实际存放到新链表中的结果是sum%10,而新的进位为sum/10。
注意:有一个容易出错的点,在循环结束后,其实所有的运算并没有结束,我们还需要判断最后一次运算有没有进位,如果有,需要再加一个val为1的节点。比如:5+5=10,如果循环结束后不进行判断,add中的进位没有用上,最后的结果将为0,这显然是不对的。
在代码的具体实现过程中,我一度纠结是应该用do-while还是while,判断的语句应该用||还是&&,条件应该是!=null还是.next!=null。说 结论:使用while,||, !=null。比较纠结的是到底应该用与还是或。最开始考虑的是用与来做,这样在循环的过程中,两个原链表都一定是非空的,这样会出现一个问题,就是循环结束后,实际上加法运算还没又结束,我需要再去判断是l1到头了还是l2到头了还是两个都到头了,不同的情况将执行不同的操作,于是我考虑直接使用或运算,在循环中对链表加一次判断,如果链表已经为空了,就让相加的值为0,不为空则使用本身的.val进行相加,指针的后移操作也再加一个判断,如果已经为空,就不再后移,如果不为空,则指向下一个。听上去似乎很复杂,但其实三目运算符就可以很好的解决这个问题。
代码
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode ret = new ListNode(-1);
ListNode now = ret;
int add = 0;
while(l1 != null || l2 != null)
{
int x = l1!=null?l1.val:0;
int y = l2!=null?l2.val:0;
int sum = x+y+add;
add = sum/10;
sum = sum%10;
ListNode temp = new ListNode(sum);
now.next = temp;
now = temp;
l1 = l1!=null?l1.next:l1;
l2 = l2!=null?l2.next:l2;
}
if(add != 0)
{
ListNode temp = new ListNode(1);
now.next = temp;
now = temp;
}
return ret.next;
}
最后再说一下,这个题目难倒我的其实是新链表的创建这一点,我一直想不明白创建了新的节点后如果不赋值就没办法让另一个节点指向它,后续操作无法进行,而如果赋值的话又会出现链表的头部有一个不应该存在的值。但其实我们只需要在返回的时候返回新创建的链表头节点.next就可以了。
最后的最后再说一下,我在最开始做这道题目的时候,把每个链表都转换成了整数值再进行计算,明明测试用例都通过了但是提交的还是不对,然后才想到使用链表来表示一个整数的话,这个整数是可以很大的,使用int、double、long都是不行的因为理论上来说链表可以无限大的(吧)。所以这个题目只能使用链表来存放链表相加的结果。