這個題目是什麼意思呢?簡單來說就是把兩個連結串列平鋪開,頭節點對齊,然後從頭開始相同的節點相加,滿10則進位,進位值與下個節點繼續相加,當一個連結串列沒有節點時候則可以把沒有節點當做0繼續與有節點的連結串列繼續相加。具體示例如下:
到這裡不知道你是否已經有解題思路了呢?
01、解法一:遞迴法
我第一反應就是遞迴,為什麼?想想題目,對兩個連結串列相同節點位置值按順序求值,第一個算完算第二個,以此類推直至所有節點計算完成,這不正好使用遞迴嗎,定義一個方法計算兩個節點和,然後以頭節點的下個節點作為遞迴點,即計算頭節點後,頭節點的下個節點計算直接呼叫自身方法直至所有節點計算完成,具體程式碼如下:
public static ListNode AddTwoNumbersRecursion(ListNode l1, ListNode l2)
{
return AddTwoNumbersRecursive(l1, l2, 0);
}
private static ListNode AddTwoNumbersRecursive(ListNode l1, ListNode l2, int carry)
{
//當兩個連結串列節點都為空並且進位值等於0,則結束遞迴
if (l1 == null && l2 == null && carry == 0)
{
return null;
}
//以進位值為初始值定義兩節點和變數,
var sum = carry;
//如果l1節點不為空,則累加其節點值,並且把其下個節點賦值給自身,用於下次迭代
if (l1 != null)
{
sum += l1.val;
l1 = l1.next;
}
//如果l2節點不為空,則累加其節點值,並且把其下個節點賦值給自身,用於下次迭代
if (l2 != null)
{
sum += l2.val;
l2 = l2.next;
}
//計算進位值
carry = sum / 10;
//以當前位值,建立下一個節點
return new ListNode(sum % 10)
{
//遞迴點
next = AddTwoNumbersRecursive(l1, l2, carry)
};
}
然後我們執行程式碼驗證一下,結果如下:
02、解法二:迭代法
我們知道因為每次遞迴都會需要額外的棧空間,因此深度遞迴可能會引發一系列效能問題,因此我們是否還有其他辦法呢?
遞迴有個同義詞叫迭代,而迭代只需要在一個迴圈裡重複執行一個計算即可,這樣就可以避免遞迴產生的問題。
因此我們只需要把遞迴方法改造成迭代方法即可,裡面的解題思路基本都是一樣的,只不過是不通的寫法。程式碼如下:
public static ListNode AddTwoNumbersIteration(ListNode l1, ListNode l2)
{
//建立頭節點,即第一位計算結果
var head = new ListNode(0);
//用於迭代節點
var current = head;
//初始化進位值
int carry = 0;
//當兩個連結串列節點都不為空並且進位值不等於0,則繼續迭代
while (l1 != null || l2 != null || carry != 0)
{
//以進位值為初始值定義兩節點和變數,
var sum = carry;
//如果l1節點不為空,則累加其節點值,並且把其下個節點賦值給自身,用於下次迭代
if (l1 != null)
{
sum += l1.val;
l1 = l1.next;
}
//如果l2節點不為空,則累加其節點值,並且把其下個節點賦值給自身,用於下次迭代
if (l2 != null)
{
sum += l2.val;
l2 = l2.next;
}
//計算進位值
carry = sum / 10;
//以當前位值,建立下一個節點
current.next = new ListNode(sum % 10);
//把下個節點賦值給當前迭代節點,繼續下次迭代
current = current.next;
}
//返回實際結果連結串列的頭節點
return head.next;
}
執行結果如下:
對於這一題核心解題思路是一樣,問題在於如何選擇方法,遞迴有遞迴的好處,迭代有迭代的好處,因此要根據自己實際情況進行選擇。
下面對遞迴和迭代做個點單對比:
遞迴:程式碼更簡潔直觀,邏輯更接近問題的自然描述易於理解;但是遞迴會消耗更多記憶體,深度遞迴可能會導致棧溢位。
迭代:節省記憶體,效能會更好;但是程式碼更難理解。
題目到這裡就做完了,但是不知道有沒有人會有這樣的疑惑?
在迭代法中,連結串列head是一個引用型別,並且被賦值給了連結串列current,而連結串列current在迭代中不停的被current.next覆蓋,那麼為什麼這個覆蓋過程沒有影響到連結串列head?導致head為整個連結串列的最後一個節點?最後返回的head.next還是正確的答案?
你知道為什麼嗎?
注: 測試方法程式碼以及示例原始碼都已經上傳至程式碼庫,有興趣的可以看看。 https://gitee.com/hugogoos/Planner