1. 程式人生 > 其它 >445.兩數相加Ⅱ

445.兩數相加Ⅱ

目錄

445.兩數相加

題目

給你兩個 非空 連結串列來代表兩個非負整數。數字最高位位於連結串列開始位置。它們的每個節點只儲存一位數字。將這兩數相加會返回一個新的連結串列。

你可以假設除了數字 0 之外,這兩個數字都不會以零開頭。

給你兩個 非空 連結串列來代表兩個非負整數。數字最高位位於連結串列開始位置。它們的每個節點只儲存一位數字。將這兩數相加會返回一個新的連結串列。

你可以假設除了數字 0 之外,這兩個數字都不會以零開頭。

示例1:

輸入:l1 = [7,2,4,3], l2 = [5,6,4]
輸出:[7,8,0,7]

示例2:

輸入:l1 = [2,4,3], l2 = [5,6,4]
輸出:[8,0,7]

示例3:

輸入:l1 = [0], l2 = [0]
輸出:[0]

提示:

連結串列的長度範圍為 [1, 100]
0 <= node.val <= 9
輸入資料保證連結串列代表的數字無前導 0

進階:如果輸入連結串列不能翻轉該如何解決?

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/add-two-numbers-ii
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

題解1

第一個問題就是如何對齊,連結串列長度是不一樣的,誰與誰相加?

長度不一樣,我們可以通過在短連結串列前面新增0節點,是兩個連結串列長度一樣,那麼頭節點對頭節點,尾節點對尾節點就對齊了。

ListNode tail1 =l1;
ListNode tail2 =l2;
//都走到最後一個節點就停止新增
while(tail1.next==null && tail2.next==null){
	if(tail1.next == null){
		//說明到尾了但是還在迴圈裡說明tail2還沒有到尾
		ListNode tmp = new ListNode(0);
		tmp.next = l1;
		l1 = tmp;
	}
	if(tail2.next == null){
		ListNode tmp = new ListNode(0);
		tmp.next = l2;
		l2 = tmp;
	}

	tail1 = tail1.next ==null ? tail1 : tail1.next;
	tail2 = tail1.next ==null ? tail2 : tail2.next;
}

處理完對齊的問題後,如何處理相加?相加是從低位開始相加,如果有進位需要向前一位傳遞。
而連結串列的遍歷順序一般是從左到右,現在我們需要從右到左,那麼可以翻轉連結串列,加完之後再翻轉回來。

//翻轉連結串列
ListNode reverseList(ListNode head){
	 ListNode pre=null;
     ListNode tmp;
        while(head!=null){
            tmp = head.next; //防止斷鏈,記錄下要反轉的節點的後一個節點
            head.next = pre; //開始反轉指向前一個
            pre = head;
            head = tmp;
        }
        return pre; //返回新的頭節點
}

開始計算,這裡的指標有點多,整理一下
tail1 指向 l1 的最後一個節點,也就是翻轉後的頭節點,l1指向翻轉後的最後一個節點
tail2 指向 l2 的最後一個節點,也就是翻轉後的頭節點,l2指向翻轉後的最後一個節點

ListNode pre = reverseList(l1);
reverseList(l2);
int flag = 0 ;//表示十位

while(tail1!=null){//長度是一樣的
tail1.val = (tail1.val +  tail2.val+flag)%10; //取個位數
flag = 	 (tail1.val +  tail2.val+flag)/10; //取十位數	
tail1 = tail.next();
}
if(flag!=0) 新增一個節點
reverseList(pre);
return l1;

程式碼
現在整理一下所有思路,發現如果先翻轉連結串列,那可以不用補節點了,翻轉之後,都從頭開始個位數自然會對齊。如果遇見null就算0。
新連結串列採用頭插法就不用再翻轉一次了。

l1 = reverseList(l1); //指向新的頭節點
l2 = reverseList(l2); //翻轉連結串列
int flag = 0 ;//表示十位
int val1=0,val2=0;
ListNode dummy = new ListNode(); //新連結串列的頭節點
ListNode tmp;
ListNode newHead;
//做加法,不同時為空,同時為空說明已經加完了
while(!(l1==null && l2==null)){
    val1 = l1 == null? 0 : l1.val;
	val2 = l2 == null? 0 : l2.val;
	tmp = dummy.next;
	newHead = new ListNode((val1 + val2+flag)%10); //取個位數
	dummy.next = newHead;
	newHead.next = tmp;
	flag = (val1 + val2+flag)/10;  //取10位數
	//遍歷下一個節點
	l1 = l1 == null? null:l1.next;
    l2 = l2 == null? null: l2.next;
}
//flag如果有值,說明進位只有還需要新增一個節點
if(flag!=0){
	newHead = new ListNode(flag);
	tmp = dummy.next;
	dummy.next = newHead;
	newHead.next = tmp;
}

return dummy.next;
	
//翻轉連結串列
ListNode reverseList(ListNode head){
	 ListNode pre=null;
     ListNode tmp;
        while(head!=null){
            tmp = head.next; //防止斷鏈,記錄下要反轉的節點的後一個節點
            head.next = pre; //開始反轉指向前一個
            pre = head;
            head = tmp;
        }
        return pre; //返回新的頭節點
}

題解2

逆序處理:還可以通過棧

總結

逆序遍歷連結串列

  • 翻轉連結串列