Golang從合併鏈表聊遞歸

從合併鏈表聊遞歸

遞歸是工程師最多見的一種解決問題的方式,可是有時候不容易真正掌握。有人說是看起來很簡單,本身寫起來會費點勁。golang

最著名的例子就是斐波那契數列(Fibonacci sequence),經過尋找遞推公式來計算出結果。
而最近刷到的一道合併鏈表的算法題,也可使用遞歸來實現。下面看看題目描述吧:算法

將兩個升序鏈表合併爲一個新的 升序 鏈表並返回。新鏈表是經過拼接給定的兩個鏈表的全部節點組成的。

示例:

輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4

來源:力扣(LeetCode)

先拋出本人觀點,遞歸的關鍵是:找到邊界條件遞歸公式性能

分析一下題目,能夠發現用第一個鏈表l1的頭部節點來去和l2的節點對比,若是大於l2的當前節點,那麼偏移l1的next和l2繼續對比大小。反之若是l1的頭節點對比L2的當前節點更小,那麼就須要對l2作相似處理。
這種不斷對比和偏移的過程,能夠總結出一種遞歸公式。
用僞代碼寫法就是:優化

if l1.val < l2.val:
    l1.next = mergeTwoList(l1.next, l2)
    
    return l1
else:
   l2.next = mergeTwoList(l1, l2.next)
   return l2

而邊界條件就是在不斷偏移的時候,走到某個鏈表的最後一個節點爲止,僞代碼就是:指針

if l1 === null:
    return l2

if l2 === null:
    return l1

用golang來實現,代碼也很清晰:code

type ListNode struct {
	Val int
	Next *ListNode
}

func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
	if l1 == nil {
		return l2
	}

	if l2 == nil {
		return l1
	}

	if l1.Val < l2.Val {
		l1.Next = mergeTwoLists(l1.Next, l2)
		return l1
	} else {
		l2.Next = mergeTwoLists(l1, l2.Next)
		return l2
	}
}

在LeetCode裏面提交,運行反饋以下:遞歸

執行結果:
經過
顯示詳情
執行用時:
0 ms
, 在全部 Go 提交中擊敗了
100.00%
的用戶
內存消耗:
2.6 MB
, 在全部 Go 提交中擊敗了
63.64%
的用戶

能夠看到遞歸是很是消耗內存的,它循環調用,猶如爾羅斯套娃,一層一層返回內層的調用結果。內存

若是要優化的話可使用迭代方式來實現,代碼須要作一些調整:ci

func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
    head := &ListNode{}
	result := head
	for l1 != nil && l2 != nil {
		if l1.Val < l2.Val {
			head.Next = l1
			head = head.Next
			l1 = l1.Next
		} else {
			head.Next = l2
			head = head.Next
			l2 = l2.Next
		}
	}

	if l1 == nil {
		head.Next = l2
	}

	if l2 == nil {
		head.Next = l1
	}

	return result.Next
}

能夠看出須要建立一個頭部指針來作偏移,而最終result做爲一個合成結果鏈表來存儲結果。
最後提交執行,發現結果數據稍微好看了一丟丟:List

執行用時:
4 ms
, 在全部 Go 提交中擊敗了
62.28%
的用戶
內存消耗:
2.5 MB
, 在全部 Go 提交中擊敗了
100.00%
的用戶

因爲在數據量不大的狀況下,其實性能差距也不大,因此使用遞歸也是沒有毛病的。

相關文章
相關標籤/搜索