上通信的課就跟室友一起刷題玩,結果讀題目讀了半天,好歹我也是過了四級的人啊,怎么能這樣,干脆百度題目意思……
題目:You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order 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.
樣例:Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
翻譯:給你兩個鏈表,然后他們的反序是一個數字(正序2也就是個位,4是十位,3是百位,然后計算他們的倆的和,和輸出也是反序,并且是一個鏈表形式
My View
我的想法是把鏈表表示的數先算出來,然后兩者相加得出答案之后轉換為鏈表,由于結果轉化為鏈表的那部分出現了一點問題,最后也沒搭理,幾天過去了竟然不想再寫,直接去solution了
solution
官方給的示意圖:
Figure 1. Visualization of the addition of two numbers: 342 + 465 = 807.
Each node contains a single digit and the digits are stored in reverse order.
到這里可能已經很深刻的理解題目的意思了。
首先我們考慮單獨相加的方法,從l1和l2的鏈表頭開始,2+5 = 7,4+6 = 10,10的話就會有進位,作為carry(攜帶)送給高位,也就是3+4+1 = 8;
那么在這里carry只可能是0或者1,這是符合我們數學邏輯的。
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
//初始化頭結點
ListNode dummyHead = new ListNode(0);
ListNode p = l1, q = l2, curr = dummyHead;
int carry = 0;
//進入鏈表循環
while (p != null || q != null) {
//記錄每個節點的值
int x = (p != null) ? p.val : 0;
int y = (q != null) ? q.val : 0;
//計算實際值(添加carry之后)
int sum = carry + x + y;
//判斷有沒有進位
carry = sum / 10;
//添加去除carry位的值
curr.next = new ListNode(sum % 10);
//移動節點
curr = curr.next;
if (p != null) p = p.next;
if (q != null) q = q.next;
}
//如果到循環結束了還余下一個carry = 1,那么就得新建一個高位,
可以參考l1=[9,9] ,l2=[1] 這種情況
if (carry > 0) {
curr.next = new ListNode(carry);
}
//最后返回dummyHead的下一個節點,(因為第一個節點是0,,java很坑吧)
return dummyHead.next;
}
上述算法的時間復雜和空間復雜都是O(max(m,n)),因為只有一層循環,
所以取決于鏈表最大長度。
正當試著提交這份代碼的時候,系統竟然判定超時,不太理解系統給的方法竟然會超時……
然后去淘discuss,發現大部分人的方法是如下的:
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
//在定義地方和上面的一致
ListNode c1 = l1;
ListNode c2 = l2;
ListNode sentinel = new ListNode(0);
ListNode d = sentinel;
int sum = 0;
//循環也是一樣的
while (c1 != null || c2 != null) {
//這里直接用sum來儲存carry和node_sum值
sum /= 10;
if (c1 != null) {
sum += c1.val;
c1 = c1.next;
}
if (c2 != null) {
sum += c2.val;
c2 = c2.next;
}
d.next = new ListNode(sum % 10);
d = d.next;
}
//這里其實和方法一一樣
if (sum / 10 == 1)
d.next = new ListNode(1);
return sentinel.next;
}
著實看不懂他倆差別在哪,除了carry與sum合并為一個之外,有知道的寶寶么?