把兩個鏈表洗牌合併成一個,系列目錄見 前言和目錄 。node
實現函數 shuffleMerge()
把兩個鏈表合併成一個。新鏈表的節點是交叉從兩個鏈表中取的。這叫洗牌合併。舉個例子,當傳入的鏈表爲 1 -> 2 -> 3 -> null
和 7 -> 13 -> 1 -> null
時,合併後的鏈表爲 1 -> 7 -> 2 -> 13 -> 3 -> 1 -> null
。若是合併過程當中一個鏈表的數據先取完了,就從另外一個鏈表中取剩下的數據。這個函數應該返回一個新鏈表。git
var first = 3 -> 2 -> 8 -> null var second = 5 -> 6 -> 1 -> 9 -> 11 -> null shuffleMerge(first, second) === 3 -> 5 -> 2 -> 6 -> 8 -> 1 -> 9 -> 11 -> null
若是參數之一爲空,應該直接返回另外一個鏈表(即便另外一個鏈表也爲空),不須要拋異常。github
代碼以下:segmentfault
function shuffleMerge(first, second) { if (!first || !second) return first || second const list = new Node(first.data, new Node(second.data)) list.next.next = shuffleMerge(first.next, second.next) return list }
解題思路是,首先判斷是否有一個鏈表爲空,有就返回另外一個,結束遞歸。這個判斷過了,下面確定是兩個鏈表都不爲空的狀況。咱們依次從兩個鏈表中取第一個節點組合成新鏈表,而後遞歸 shuffleMerge
兩個鏈表的後續節點,並把結果銜接到 list
後面。這段代碼基本跟題目描述的意思一致。函數
在上面的基礎上咱們還能作個更聰明的版本,代碼以下:測試
function shuffleMergeV2(first, second) { if (!first || !second) return first || second return new Node(first.data, shuffleMerge(second, first.next)) }
經過簡單的調換 first
和 second
的順序,咱們能把遞歸過程從 「先取 first 的首節點再取 second 的首節點」 變成 「總老是取 first 的首節點」 。解法 1 中的三行代碼簡化成了一行。指針
循環其實才是本題的考點,由於這題主要是考指針(引用)操做。尤爲是把 「依次移動兩個鏈表的指針」 寫進一個循環裏。不過上個解法中調換兩個鏈表順序的方式也能夠用到這裏。代碼以下:code
function shuffleMergeV3(first, second) { const result = new Node() let pr = result let [p1, p2] = [first, second] while (p1 || p2) { if (p1) { pr.next = new Node(p1.data) pr = pr.next p1 = p1.next } [p1, p2] = [p2, p1] } return result.next }
首先咱們生成一個 dummy node result
,同時創建一個 pr
表明 result
的尾節點(方便插入)。兩個鏈表的指針分別叫 p1
和 p2
。在每次循環中咱們都把 p1
的節點數據寫到 result
鏈表的末尾,而後修改指針指向下一個節點。經過 12 行的調換指針,咱們能夠保證下一次循環就是對另外一個鏈表進行操做了。這樣一直遍歷到兩個鏈表末尾,返回 result.next
結束。遞歸