题目描述


给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

例如:
No.2 两数之和 (Medium) - 图1
解释:
因为是逆序保存的,所以2->4->3表示数字342, 同理得到465
342 + 465 = 807, 因此得到7->0->8

注意,两个链表并不一定长度相同,即可能20 + 300 = 320。

思路

首先理解为什么要用倒序表示一个数,因为链表只能从头结点开始遍历,分别表示个,十,百,千 … 因此只有倒序时,才符合我们的数学计算规则,从个位开始计算和,然后说十位,百位 …

该题的几个难点:

  1. 进位如何处理
  2. 不同长度的链表如何处理

难点1:进位如何处理

  1. if (有进位) {
  2. sum = value1 + value2 + 进位;
  3. } else {
  4. sum = value1 + value2;
  5. }
  6. // 简化版本
  7. int carry = 0;
  8. while () {
  9. sum = value1 + value2 + carry;
  10. carry = sum / 10;
  11. sum = sum % 10;
  12. }

此为,如果 两个链表都遍历完了,最高位仍然有进位,需要再最高位补1

难点2: 不同长度的链表如何处理

对短链表的高位补0,例如240 + 32 = 240 + 032

小技巧

在处理链表问题时,通常会在头结点(Head)前面初始化一个dummy node, 主要原因是链表通常会涉及到指针的移动,例如在遍历之后,指针指向了最后一个结点,那么怎么返回该链表的头结点呢?技巧就是添加一个dummy node指向链表的头结点,那么最后只需要返回dummy.next即可。

代码

  1. class Solution {
  2. public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
  3. ListNode dummy = new ListNode(0);
  4. // current首先指向dummy, 在遍历过程中仅移动current, 不再移动dummy
  5. ListNode current = dummy;
  6. // 初始化carry为0
  7. int carry = 0;
  8. // 循环停止的条件为两个链表都为null
  9. while (l1 != null || l2 != null) {
  10. // 当l1或者l2不为空时,value值即结点的值
  11. // 为空时,value值为0,就相当于是短的链表已经遍历到最后了,指向null了
  12. int value1 = l1 == null ? 0 : l1.val;
  13. int value2 = l2 == null ? 0 : l2.val;
  14. // 求和,该和可能大于10,产生新的carry
  15. int sum = value1 + value2 + carry;
  16. // 计算新的carry,例如,sum = 16, carry = 16 / 10 = 1;
  17. // Java中,两个整数相除,商为整数,直接丢弃了小数位
  18. carry = sum / 10;
  19. // 对sum取余得到新的sum, sum = 16, sum = 16 % 10 = 6;
  20. sum = sum % 10;
  21. // current的next指向新的结点
  22. current.next = new ListNode(sum);
  23. // current指向新结点
  24. current = current.next;
  25. // 移动l1和l2
  26. if (l1 != null) {
  27. l1 = l1.next;
  28. }
  29. if (l2 != null) {
  30. l2 = l2.next;
  31. }
  32. }
  33. // 如果都遍历完了,仍然有进位,需要最后补上进位结点
  34. // 事实上,两个个位数想加,carry最大也只会说1
  35. // 例如 999 + 999 即便每一位都是最大值,每一位都有进位,最高位也是9 + 9 + 1 = 19
  36. // 最高位的进位也不会超过1
  37. if (carry != 0) {
  38. current.next = new ListNode(carry);
  39. }
  40. return dummy.next;
  41. }
  42. }