從零打卡leetcode之day 2---兩數相加

帥地發表於2018-08-13

前言

就是要把leetcode刷完,每天一道題,每天進步一點點。


從零打卡leetcode之day 2

題目描述:

給定兩個非空連結串列來表示兩個非負整數。位數按照逆序方式儲存,
它們的每個節點只儲存單個數字。將兩數相加返回一個新的連結串列。

你可以假設除了數字 0 之外,這兩個數字都不會以零開頭。
示例:
輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出:7 -> 0 -> 8
原因:342 + 465 = 807

我的想法

我靠,居然還用到了連結串列的知識,突然就想起了當初用c語言自學連結串列的那段日子,真的差點被搞死。各種指標指來指去的。

好吧,我這裡需要宣告一下,如果你還沒接觸過連結串列,或者對連結串列超級不熟悉,麻煩你先去學好連結串列再來刷題,因為,連結串列是真的賊重要啊。

正文

方法1:

說實話,看到這道題的時候,我的想法是不管三七二十一,直接把連結串列代表的數字給直接算出來,然後在把兩個數字給加起來,最後在把得到的和拆分成連結串列。可謂是暴力思路又簡單啊。不過感覺程式碼量會有點多。

例如:

(2 -> 4 -> 3) => 2 + 4 * 10 + 3 * 100 = 342 
(5 -> 6 -> 4) => 5 + 6 * 10 + 4 * 100 = 465
然後
342 + 465 = 807
接著
807 => 7 -> 0 -> 8

程式碼如下所示:

先給出連結串列的結構

 class ListNode {
     int val;
     ListNode next;
     ListNode(int x) { val = x; }
 }
 //方法1
 public ListNode addTwoNumbers1(ListNode l1, ListNode l2) {
     int num1 = 0;//用來存放第一個連結串列代表的數字
     int num2 = 0;//用來存放第二個連結串列代表的數字
     int sum = 0;//存放和
     //t = 1,10,100....用來代表連結串列中的個位,十位,百位...
     int t = 1;//因為是從個位開始遍歷的,所以初值為1
     //算第一個數字
     while(l1 != null){
         num1 = num1 + l1.val * t;
         t = t * 10;
         l1 = l1.next;
     }
     t = 1;
     //算第二個數字
     while(l2 != null){
         num2 = num2 + l2.val * t;
         t = t * 10;
         l2 = l2.next;
     }
     //相加
     sum = num1 + num2;
     //拆分出來放進連結串列裡;
     ListNode head  = null;//作為連結串列的頭節點
     ListNode temp = head;//跟蹤連結串列
     while(sum > 0) {//結束條件為sum等於0
         if(head == null){
             head = new ListNode(sum % 10);
             temp = head;
         }else{
             temp.next = new ListNode(sum % 10);
             temp = temp.next;
         }
         sum = sum / 10;
     }
     //由於有可能sum一開始就為0,所以還需要在檢查一下
     if(head == null){
         head = new ListNode(0);
     }
     return head;
    }

大家一起探討探討,你們覺得這種思路可行嗎?覺得可行的舉個爪,不可行的站起來說說為啥不可行。

反正,我是覺得不可行,為什麼?

因為題目並沒有說這條連結串列有多長啊,假如這條連結串列很長的話,一個int型整數根本存不了這個數字,當然,你可能會說,我可以用long long啊。 不好意思,long long也可能存不了。你可能又會說,java或python什麼的,不是有大整數咪?好吧,我沒去用過這些大整數,不知道具體個什麼情況,所以當作沒有這麼一回事處理,haha。有興趣的可以去嘗試一下。


方法2

剛才方法1已經被告知不可行了。實際上,這道題我是覺得在解法思路上還是比較簡單的,我相信大家也都能想到方法2這種方法:

就是我們可以讓兩個數的個位數相加,十位數相加….然後個位數有進位的話,再把進位給十位數….

例如:

(1 -> 4 -> 5) + (1 -> 6 -> 4 -> 5)
(我是故意給出兩條連結串列長度不相等的情況的)

解法如下圖:

程式碼如下:

      int cout = 0;//用來檢查是否有進位,預設沒有進位
        ListNode head = null;//用來作為連結串列頭
        ListNode temp = head;//用來跟蹤連結串列
        //注意迴圈結束條件
        while(l1 != null && l2 != null){
            if(head == null){
                head = new ListNode((l1.val + l2.val + cout) % 10);
                temp = head;
            }else{
                temp.next = new ListNode((l1.val + l2.val + cout) % 10);
                temp = temp.next;
            }
            //檢查是否有進位
            cout = (l1.val + l2.val + cout) / 10;
            l1 = l1.next;
            l2 = l2.next;
        }
        while(l1 != null){
            temp.next = new ListNode((l1.val + cout) % 10);
            cout = (l1.val + cout) / 10;
            l1 = l1.next;
            temp = temp.next;
        }
        while(l2 != null){
            temp.next = new ListNode((l2.val + cout) % 10);
            cout = (l2.val + cout) / 10;
            l2 = l2.next;
            temp = temp.next;

        }
        //最後還得在檢測一下時候最高位有進位
        if(cout == 1){
            temp.next = new ListNode(cout);
        }
        return head;

這裡需要注意的一些點:

  1. 就是第一個迴圈的結束條件.

  2. 當迴圈結束之後,還得把那條比較長的連結串列剩餘的部分再迴圈一遍。

  3. 最後還得看一下是否最高位有進位。

我覺得這道題在解法思路上還是比較簡單,不過並不意味著做起來簡單,因為這道題如果不仔細看,還是很容易出錯的,細節點不叫多。

不過

除了方法二,我是不知道還要其他什麼比較好的方法了,但是我是覺得方法二里面的程式碼有點多,於是絞盡腦汁,各種簡化,寫出了一份程式碼比較簡練的精簡程式碼。放出來給各位看看:

//作為頭節點,且最後返回時不要這個頭節點
        ListNode head = new ListNode(0);
        ListNode temp = head;//跟蹤
        int cout = 0;

        while(l1 != null || l2 != null || cout != 0){
            if(l1 != null){
                cout += l1.val;
                l1 = l1.next;
            }
            if(l2 != null){
                cout += l2.val;
                l2 = l2.next;
            }
            temp.next = new ListNode(cout % 10);
            temp = temp.next;
            cout = cout / 10;
        }
        return head.next;

先得意一下:雖然大家都能想到方法二,不過我就不信你能比我的簡潔。哈哈哈

幾點說明:

  1. 先把頭節點直接new出來,可以省略判斷語句。
  2. 以前的while迴圈是判斷兩個連結串列都不為空,不過我現在換了一種想法,因為i你想我,只要有一個連結串列是不為空的,或者只要coun=1,那麼我們就得繼續處理,於是乎…..

此題到此結束


相關文章