1. 程式人生 > >【LeetCode題解---2】Add Two Numbers.md

【LeetCode題解---2】Add Two Numbers.md

【LeetCode題解—2】Add Two Numbers

題目

  • 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.

    Example:

    Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
    Output: 7 -> 0 -> 8
    Explanation: 342 + 465 = 807.
    

詞彙

non-empty 非空 non-negative 非負 reverse相反 digits 數字 stored in reverse 反向儲存 each of 每一個 nodes 節點

翻譯

​ 本題主要是類似資料在機器中儲存的方式,我們平常所見的資料比如342,在連結串列中是逆向儲存的所以就成了2->4->3這樣了,同樣5 -> 6 -> 4就是465, ​ 如果這樣轉換後,我們就會發現342+465=807,在十位上相加是超過10向前進一,但是連結串列是逆向的,所以就是向後進一。 ​ 因此,本題可以把連結串列中的元素轉換為相應的資料後進行相加,得到的結果在按照相應的格式放入連結串列中,這種方式會很麻煩。應該重新建立一個連結串列,儲存每個節點相加和進位的和。最後應該判斷,進位標誌位是否任然不為0,這時應該繼續建立新的節點,並將進位標誌作為節點的值

解法-Java

解法一

  • 由於加法需要從最低位開始運算,而最低位在連結串列末尾,連結串列只能從前往後遍歷,沒法取到前面的元素,那怎麼辦呢?
  • 我們可以利用棧來儲存所有的元素,然後利用棧的後進先出的特點就可以從後往前取數字了,
  • 我們首先遍歷兩個連結串列,將所有數字分別壓入兩個棧s1和s2中,我們建立一個值為0的head節點,
  • 然後開始迴圈,如果棧不為空,則將棧頂數字加入sum中,然後將res節點值賦為sum%10,
  • 然後新建一個進位節點point,賦值為sum/10,如果沒有進位,那麼就是0,
  • 然後我們head後面連上res,將res指向head,這樣迴圈退出後,
  • 我們只要看res的值是否為0,為0返回res->next,不為0則返回res即可
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {

        // 邊界條件判斷
        if (l1 == null) {
            return l2;
        }else if (l2 == null) {
            return l1;
        }

        ListNode head = new ListNode(0);
        ListNode point = head;
        int carry = 0;
        while (l1 != null && l2 != null) {
            int sum = carry + l1.val + l2.val;
            ListNode rest = new ListNode(sum % 10);
            point.next = rest;
            carry = sum / 10;
            l1 = l1.next;
            l2 = l2.next;
            point = point.next;
        }

        while (l1 != null) {
            int sum = carry + l1.val;
            ListNode rest = new ListNode(sum % 10);
            point.next = rest;
            carry = sum / 10;
            l1 = l1.next;
            point = point.next;
        }

        while (l2 != null) {
            int sum = carry + l2.val;
            point.next = new ListNode(sum % 10);
            carry = sum / 10;
            l2 = l2.next;
            point = point.next;
        }

        if (carry != 0) {
            point.next = new ListNode(carry);
        }
        return head.next;
    }

解法二

遍歷兩個連結串列,把各個位數相加,注意進位

public static ListNode addTwoNumbers2(ListNode l1, ListNode l2) {
        // 邊界條件判斷
        if (l1 == null) {
            return l2;
        }else if (l2 == null) {
            return l1;
        }

        ListNode list = null;
        ListNode next = null;
        // 記錄和值
        int sum = 0;
        // 記錄是否有進位
        int b = 0;
        while (l1 != null || l2 != null) {
            if (l1 != null) {
                sum = l1.val;
                l1 = l1.next;
            }
            if (l2 != null) {
                sum += l2.val;
                l2 = l2.next;
            }
            sum += b;
            b = sum / 10;
            // 如果不利用 / 和 % 的話 此處對於 b 和 sum 的賦值就要根據如下注釋掉的方式去做
            // 有一丟丟麻煩
            // 解法3 中會使用這種方式
            /*if (sum > 9) {
                // 和值大於9 則代表有進位
                sum -= 10;
                //b = 1;
            } else {
                // 無進位
                //b = 0;
            }*/
            if (list == null) {
                list = new ListNode(sum % 10);
                next = list;
            } else {
                next.next = new ListNode(sum % 10);
                next = next.next;
            }
            sum = 0;
        }
        if (b == 1) {
            next.next = new ListNode(b);
        }
        return list;
    }

解法三

只遍歷較短的連結串列,剩下的較長連結串列可以直接新增

public static ListNode addTwoNumbers3(ListNode l1, ListNode l2) {
        // 邊界條件判斷
        if (l1 == null) {
            return l2;
        }else if (l2 == null) {
            return l1;
        }

        ListNode list = null;
        ListNode next = null;
        ListNode cl1 = l1.next;
        ListNode cl2 = l2.next;
        while (true) {
            if (cl1 == null) {
                cl1 = l1;
                cl2 = l2;
                break;
            } else if (cl2 == null) {
                cl1 = l2;
                cl2 = l1;
                break;
            } else {
                cl1 = cl1.next;
                cl2 = cl2.next;
            }
        }

        int sum = 0;
        int b = 0;
        while (cl1 != null) {
            sum = cl1.val + cl2.val + b;
            cl1 = cl1.next;
            cl2 = cl2.next;

            if (sum > 9) {
                sum -= 10;
                b = 1;
            } else {
                b = 0;
            }

            if (list == null) {
                list = new ListNode(sum);
                next = list;
            } else {
                next.next = new ListNode(sum);
                next = next.next;
            }
            sum = 0;
        }

        next.next = cl2;
        while (b == 1) {
            if (cl2 == null) {
                next.next = new ListNode(b);
                break;
            }
            sum = cl2.val + b;
            if (sum > 9) {
                sum -= 10;
                b = 1;
            } else {
                b = 0;
            }
            cl2.val = sum;
            cl2 = cl2.next;
            next = next.next;
        }
        return list;
    }

解法-Python

解法一

  1. 定義節點。使用:類+構造方法,構造方法的引數要有節點的數值大小、對下一個節點的指標等。
  2. 若 l1 表示一個連結串列,則實質上 l1 表示頭節點的指標。
  3. 先例項一個頭結點,然後在 while 迴圈中逐個加入節點
  4. del ret 刪除頭結點
#題目中定義的單鏈表類的結構如下:
#class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        l1,l2為輸入的待加和的兩個串
        """
        
        #將兩個單鏈表串按位掃到列表listnum1和listnum2中
        listnum1 = []
        listnum2 = []
        while l1 != None:
            listnum1.append(l1.val)
            l1 = l1.next
        while l2 != None:
            listnum2.append(l2.val)
            l2 = l2.next
        
        #將兩個數用整型num1和num2表示出來(**運算為指數運算,eg. 2 ** 3 結果為8)
        num1 = 0
        num2 = 0
        for i in range(len(listnum1)):
            num1 = listnum1[i] * (10 ** i) + num1
        for j in range(len(listnum2)):
            num2 = listnum2[j] * (10 ** j) + num2
            
        #計算結果後,構造結果的單鏈表結構l3
        result = num1 + num2
        l3 = ListNode(0)
        p = ListNode(0)
        p = l3
        #l3和p指向首節點,構造過程中l3不動,仍指向首節點,p進行構造移動
        while result >= 10:
            temp = ListNode(None)
            p.val = result % 10
            p.next = temp
            p = temp
            result = result / 10
        #由於迴圈到最後一個節點時不再構造新節點,於是退出迴圈,並給最後一個節點賦值
        p.val = result % 10
        return l3