问题描述
- You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes first and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Follow up:
What if you cannot modify the input lists? In other words, reversing the lists is not allowed. - Example:
Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 8 -> 0 -> 7
问题分析
- 该题是 LeetCode 2. Add Two Numbers 的进阶题,原题是最低位在链表头部,该题是最高位在链表头部。如果反转链表后计算的话,十分容易,但题目要求不能反转链表,再加上这是链表,不是数组,所以相对麻烦一些
- 解法1 : 用栈实现“反转链表”的功能
- 解法2 : 用递归(实际还是栈)
- 解法3: 利用找新链表中的最右边的第一个非 9 的节点,来处理进位信息
其实方法还是来源于 LeetCode 的另一道题目,[LeetCode] Plus One Linked List 链表加一运算 , 以及 LeetCode 66. Plus One
思路是遍历链表,找到右起第一个不为9的数字,如果找不到这样的数字,说明所有数字均为9,那么在表头新建一个值为0的新节点,进行加1处理,然后把右边所有的数字都置为0即可。举例来说:
比如1->2->3,那么第一个不为9的数字为3,对3进行加1,变成4,右边没有节点了,所以不做处理,返回1->2->4。
再比如说8->9->9,找第一个不为9的数字为8,进行加1处理变成了9,然后把后面的数字都置0,得到结果9->0->0。
再来看9->9->9的情况,找不到不为9的数字,那么再前面新建一个值为0的节点,进行加1处理变成了1,把后面的数字都置0,得到1->0->0->0。
至于该题的情况,有进位就需要将新链表(尚未加入当前产生进位信息的节点)加1 ,所以只要实时维护新链表中右起第一个不为9的数字的位置即可。有进位时,该位置加1,该位置后面所有值都为0。更加复杂。
并且,还要注意虚拟节点的使用。
经验教训
- 递归处理链表问题,还是十分好用的
- 解法3这种奇淫技巧!!!
代码实现
- 解法1
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if (l1 == null || l2 == null) {
return null;
}
ListNode cur1 = l1;
ListNode cur2 = l2;
Stack<Integer> s1 = new Stack<>();
Stack<Integer> s2 = new Stack<>();
ListNode addedList = null;
while (cur1 != null) {
s1.push(cur1.val);
cur1 =cur1.next;
}
while (cur2 != null) {
s2.push(cur2.val);
cur2 = cur2.next;
}
int carry = 0;
while (!s1.isEmpty() || !s2.isEmpty()) {
int val = 0;
if (!s1.isEmpty()) {
val += s1.pop();
}
if (!s2.isEmpty()) {
val += s2.pop();
}
val += carry;
ListNode newHead = new ListNode(val % 10);
newHead.next = addedList;
addedList = newHead;
carry = val / 10;
}
if (carry != 0) { //处理进位信息
ListNode newHead = new ListNode(1);
newHead.next = addedList;
return newHead;
}
return addedList;
}
- 解法2
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if (l1 == null || l2 == null) {
return null;
}
int length1 = getLength(l1);
int length2 = getLength(l2);
//确保长链以及短链
ListNode res = length1 > length2 ? addTwoNumbers(l1, l2, length1 - length2) : addTwoNumbers(l2, l1, length2 - length1);
//处理最高位信息
if (res.val > 9) {
res.val = res.val % 10;
ListNode newHead = new ListNode(1);
newHead.next = res;
return newHead;
}
return res;
}
//统计长度
public int getLength(ListNode head) {
ListNode curNode = head;
int length = 0;
while (curNode != null) {
++length;
curNode = curNode.next;
}
return length;
}
//已知 l1长度大于l2长度offset,对两链表进行"相加", 9 -> 6 -> 3 与 5 - > 8 相加结果为 10 -> 2 -> 1
//也就是对最高位的进位不处理
public ListNode addTwoNumbers(ListNode l1, ListNode l2, int offset) {
//base case
if (l1 == null) {
return null;
}
//当前位的相加结果
ListNode curRes = offset == 0 ? new ListNode(l1.val + l2.val) : new ListNode(l1.val);
//递归得出 下一位的相加结果
ListNode nextRes = offset == 0 ? addTwoNumbers(l1.next, l2.next, offset) : addTwoNumbers(l1.next, l2, offset - 1);
//根据下一位的结果,修正当前结果以及下一位结果
if (nextRes != null && nextRes.val > 9) {
curRes.val += 1;
nextRes.val = nextRes.val % 10;
}
//连接
curRes.next = nextRes;
//返回整体相加后结果
return curRes;
}
- 解法3
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if (l1 == null || l2 == null) {
return null;
}
int diff = getLength(l1) - getLength(l2);
//让 l1指向长链表,l2指向短链表
if (diff < 0) {
ListNode temp = l1;
l1 = l2;
l2 = temp;
}
diff = Math.abs(diff);
//虚拟节点
ListNode dummy = new ListNode(0);
//新形成链表的尾部
ListNode tail = dummy;
//指向新链表中 :从右起第一个不为9的节点(它的后面全是 9)
ListNode lastNot9 = dummy;
ListNode cur1 = l1;
//将长链表多于的一部分(不参与加法)直接加入新链表,并更新lastNot9
while (diff > 0) {
tail.next = new ListNode(cur1.val);
tail = tail.next;
if (tail.val != 9) {
lastNot9 = tail;
}
cur1 = cur1.next;
--diff;
}
//两链表相加
ListNode cur2 = l2;
while (cur1 != null) {
int val = cur1.val + cur2.val;
//如果当前值大于10
if (val >= 10) {
val -= 10;
//新链表中,从右起第一个不为9的节点加1,进位的原因
++lastNot9.val;
//该节点后面节点全部置为0,因为原先都为9,一发生进位变为0
ListNode is9 = lastNot9.next;
while (is9 != null) {
is9.val = 0;
is9 = is9.next;
}
}
tail.next = new ListNode(val);
//更新lastNot9
lastNot9 = val != 9 ? tail.next : lastNot9;
tail = tail.next;
cur1 = cur1.next;
cur2 = cur2.next;
}
//dummy.val == 1 说明 原链表中第一位相加后结果为9,但因进位,又多了一位。
return dummy.val == 1 ? dummy : dummy.next;
}
//统计长度
public int getLength(ListNode head) {
ListNode curNode = head;
int length = 0;
while (curNode != null) {
++length;
curNode = curNode.next;
}
return length;
}