玩轉演算法面試之連結串列

joytoy發表於2021-09-09

206 Reverse Linked List

圖片描述

  • 反轉連結串列。
  • 一般遇到這種題,入門的大概思路是利用棧儲存,然後再反向彈出賦值更新(改變連結串列中的值),不過這種思路是錯誤的。
  • 那我先把頭結點指向Null? 錯,因為這樣我們就拿不到2這個節點了。
  • 圖片描述
  • 我們需要三個指標來幫我們解決問題。(pre,cur,next)三個節點依次向前移動
  • 圖片描述
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    let pre = null
    while (head) {
        // 儲存下一個結點
        next = head.next
        // 反轉指標方向
        head.next = pre
        // 節點遞增
        pre = head
        head = next
    }
    return pre
};

92. Reverse Linked List II

反轉一個連結串列從m到n的元素。
如對於連結串列1->2->3->4->5->NULL,m=2,n=4。則返回連結串列1->4->3->2->5->NULL

  • m和n超過連結串列範圍怎麼辦? m和n是負值怎麼辦?
  • m>n怎麼辦?
  • m=1.或者n是最後一個
var reverseBetween = function(head, m, n) {
    if(m >= n) {
        return head;
    }
    
    var dummy = new ListNode(0);  //透過構建listNode,處理m==1的情況
    dummy.next = head;
    head = dummy;
    
    // 移動head到m-1的node;
    for(var i = 0; i 

83. Remove Duplicates from Sorted List

給出一個有序連結串列,刪除其中所有重複元素,使得每個元素只保留一次。

  • 如1->1->2,返回1->2
  • 如1->1->2->3->3,返回1->2->3

86. Partition List

給出一個連結串列以及一個數x,將連結串列重新整理,使得小於x的元素在前;大於等於x的元素在後。

  • 如1->4->3->2->5->2,×=3
  • 返回1->2->2->4->3->5
  • 左邊和右邊的順序是任意還是需要保持原有連結串列的順序

328. Odd Even Linked List

給出一個連結串列,將連結串列重新整理,使得所有索引為奇數的節點排在索引為偶數的節點前面。

  • 如1->2->3->4->5->NULL
  • 返回1->3->5->2->4->NULL
  • 第一個節點的索引為1
  • 奇數索引的節點和偶數索引的節點在重新整理後要保持相對順序。

2. Add Two Numbers

給出兩個非空連結串列,表示兩個非負整數。其中每一個整數的各位數字以逆序儲存,返回這兩個整數相加所代表的連結串列。

  • 如342+465=807
  • 則給出2->4->3和5->6->4,返回7->0->8
  • 數字中是否有前置的零。(除零以外,沒有前置零)
  • 當我們遇到字串表示數字的情況時,要考慮負數。本文因為已經支援非負整數

445. Add Two Numbers II

給出兩個非空連結串列,表示兩個非負整數。其中每一個整數的各位數字以順序儲存,返回這兩個整數相加所代表的連結串列。

  • 如342+465=807
  • 則給出3->4->2和4->6->5,返回8->0->7
  • 不允許修改輸入的連結串列
  • 使用輔助資料結構

設立連結串列的虛擬頭節點

203. Remove Linked List Elements

在連結串列中刪除值為val的所有節點

  • 如1->2->6->3->4->5->6->NULL,要求刪除值為6的節點
  • 返回1->2->3->4->5->NULL
    圖片描述
  • 對刪除第一個元素不適用,不過我們可以拿出來單獨判斷頭節點,但是這樣就產生了兩個刪除邏輯,所以這個時候就需要dummy虛擬節點,這樣對連結串列中的所有節點都可以統一了
    圖片描述
var removeElements = function(head, val) {
    if(head === null){
        return head;
    }
    
    var dummy = new ListNode(-1);
    dummy.next = head;
    prev = dummy;
    cur = head;
    
    while(prev !== null && prev.next !== null){
		// 如果當前元素等於要刪除元素,刪除
        if(cur.val === val) {
            prev.next = cur.next;
            cur = prev.next;
        } else {
            prev = cur;
            cur = cur.next;
        }
    }
    
    return dummy.next;
};

虛擬頭節點技巧鞏固

82. Remove Duplicates from Sorted Listed II

給定一個有序連結串列,將其中有重複的元素全部刪除。

  • 如1->2->3->3->4->4->5,返回1->2->5
  • 如1->1->1->2->3,返回2->3

21. Merge Two Sorted Lists

merge兩個有序的連結串列

24. Swap Nodes in Pairs

給定一個連結串列,對於每兩個相鄰的節點,交換其位置。

  • 如:連結串列為1->2->3->4->NULL
  • 返回:2->1->4->3->NULL
  • 只能對節點進行操作,不能修改節點的值
  • 下圖next是不必要指標,但是去除最佳化效果不大

圖片描述
圖片描述

var swapPairs = function(head) {
    var dummy = new ListNode(0);
    dummy.next = head;
    var n1 = dummy;
    var n2 = head;
    // 確認還有節點可以交換
    while(n2 !== null && n2.next !== null){
        // 儲存next節點,防止丟失
        var nextStart = n2.next.next;
        // 交換
        n1.next = n2.next;
        n1.next.next = n2;
        n2.next = nextStart;
        
        n1 = n2;
        n2 = n2.next;
    }
    
    return dummy.next;
};

25. Reverse Nodes in k-Group

給定一個連結串列,每k個節點為一組,反轉每一組的k個節點。k為正整數且小於等於連結串列長度。如果連結串列長度不是k的整數倍,剩餘部分不需要進行反轉。如:1->2->3->4->5->NULL

  • 若k=2,則結果為:2->1->4->3->5->NULL
  • 若k=3,則結果為:3->2->1->4->5->NULL

147. Insertion Sort List

為一個連結串列進行插入排序

148. Sort List

寫一個排序演算法,用0(nlogn)的時間複雜度為一個連結串列進行排序
歸併排序

237. Delete Node in a Linked List

給定連結串列中的一個節點,刪除該節點
難點:不可能拿到刪除節點的前一個節點
解決思路: deleteNode = deleteNode->next, 然後刪除deleteNode->next(老辦法)

var deleteNode = function(node) {
	if(node == null) return;

    if(node.next === null){
	    node.val = null;
        return;
    }
    
    node.val = node.next.val;
    node.next = node.next.next;
};

雙指標技術

19. Remove Nth Node From End of List

給定一個連結串列,刪除倒數第n個節點

  • 如:1->2->3->4->5->NULL,n=2
  • 返回:1->2->3->5
  • n從0計還是從1計
  • n不合法,負數或者大於連結串列長度如何處理(保證n合法)

解法1:先遍歷一遍計算連結串列長度;再遍歷一遍刪除倒數第n個節點

  • 遍歷兩遍連結串列。能否只遍歷一遍連結串列?
  • 藉助兩個指標: 兩個指標間的距離相等

圖片描述

var removeNthFromEnd = function(head, n) {
    var n1 = new ListNode();
    var n2 = new ListNode();
    var dummy = n2;
    
    n1.next = head;
    n2.next = head;
    // 這裡判斷n1是為了防止傳入的n比連結串列總長度還要長
    while(n > 0 && n1){
        n1 = n1.next;
        n--;
    }
    // 說明n確實比連結串列還要長。
    if(n > 0){
        return head;
    }
    // 經過上面的迴圈,n1和n2已經相差了n個結點
    while(n1 && n1.next){
        n1 = n1.next;
        n2 = n2.next;
    }
    // 刪除
    n2.next = n2.next.next;
    
    return dummy.next;
};

61. Rotate List

給定一個連結串列,讓這個連結串列向右旋轉k位。其中k為非負數。
如:1->2->3->4->5->NULL,k=2

  • 第一次旋轉:5->1->2->3->4->NULL
  • 第二次旋轉:4->5->1->2->3->NULL

143.Reorder List

給定一個連結串列L(0)>L(1)>L(2)>.…>L(n-1)>L(n)
將其變為L(O)>L(n)->L(1)->L(n-1)->L(2)->L(n-2)……的形式

  • 連結串列無法隨機訪問資料,如何獲得中間的元素?
  • 兩次遍歷可以,但是一次遍歷怎麼獲取?

234.Palindrome Linked List

給一個連結串列,判斷這個連結串列是否為迴文連結串列。

  • 能否使用0(1)的空間複雜度解決問題?

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4650/viewspace-2814742/,如需轉載,請註明出處,否則將追究法律責任。

相關文章