別說鏈表不重要(三):鏈表高頻面試題、經典問題一篇搞定

鏈表高頻面試題、經典問題

關於我

經典問題

在閱讀了單鏈表原理雙指針技技巧後,我們仍然在LeeCode上找出幾個經典面試題,以此加強掌握。

一、反轉鏈表

思路

我們接受到鏈表 [1, 2, 3, 4, 5]

  1. 首先,我們將head結點的下一個結點(即結點 2)移動到列表的頭部pre
    在這裏插入圖片描述

  2. 然後,我們將黑色結點的下一個結點(即結點 3)移動到列表的頭部:
    在這裏插入圖片描述

直至當前鏈表遍歷到尾部。

在實際操作中,你需要:

  • 時刻保存pre節點,即前一個節點。
  • 時刻保存下一個節點,因爲她要成爲新的頭節點

時間複雜度爲 O(N)
空間複雜度爲 O(1)

代碼

var reverseList = function(head) {
    let cur = head //  當前節點
    let prev = null //  前置節點初始化(head節點無前置節點)
    while (cur) {
        let temp = cur.next // 記錄當前節點的後置所有節點
        cur.next = prev // 記錄上一個節點
        prev = cur // 每一步移動後的結果: 1->null | 2->1->null...
        cur = temp // 鏈表向後一位
    };
    return prev
};

二、移除鏈表元素

刪除鏈表中等於給定值 val 的所有節點。

示例:

輸入: 1->2->6->3->4->5->6, val = 6
輸出: 1->2->3->4->5

思路

  • 創建一個啞節點來保存鏈表,以方比較頭節點
  • 如果保存的值與給定的值相等,則跳過該節點,否則向後比較

代碼

var removeElements = function(head, val) {
    if (head == null) return null;
    var temp = {
        val: -1,
        next: head
    }
    var search = temp;
    while (search.next) {
        if (search.next.val == val) {
            search.next = search.next.next;
        } else {
            search = search.next;
        }
    }
    return temp.next;
};

三、奇偶鏈表

給定一個單鏈表,把所有的奇數節點和偶數節點分別排在一起。請注意,這裏的奇數節點和偶數節點指的是節點編號的奇偶性,而不是節點的值的奇偶性。

請嘗試使用原地算法完成。你的算法的空間複雜度應爲 O(1),時間複雜度應爲 O(n),n 爲節點總數。

示例 1:

輸入: 1->2->3->4->5->NULL
輸出: 1->3->5->2->4->NULL

示例 2:

輸入: 2->1->3->5->6->4->7->NULL 
輸出: 2->3->6->7->1->5->4->NULL

說明:

應當保持奇數節點和偶數節點的相對順序。
鏈表的第一個節點視爲奇數節點,第二個節點視爲偶數節點,以此類推。

思路

  • 定義三個指針,分別記錄奇數鏈表、偶數鏈表、偶數鏈表的head節點
  • 記錄奇偶鏈表,最後將偶數鏈表接到奇數鏈表的尾端
    • 奇數鏈表節點 = 偶數鏈表最新節點的下一個
    • 偶數鏈表節點 = 奇數鏈表最新節點的下一個

代碼

var oddEvenList = function(head) {
    if(!head) return ;
    var odd = head; // 奇數鏈表
    var even = head.next; // 偶數鏈表
    var evenHead = even // 偶數鏈表頭
    while(even && even.next ){
        odd.next = even.next
        odd = odd.next
        even.next = odd.next
        even = even.next
    }
    odd.next = evenHead
    return head
};

四、迴文鏈表

思路

  • 利用快慢指針確定鏈表的中間位置;
  • 將鏈表的前半部分進行反轉,與鏈表的後半部分進行比對;

代碼

var isPalindrome = function(head) {
    if(!head || !head.next) return true;
    var slow = head // 慢指針
    var fast = head // 快指針
    var prev = null // 保存上一個節點
    var temp = null // 保存下一個節點
    while(fast && fast.next){
        fast = fast.next.next // 快指針走2個節點

        temp = slow.next // 慢指針走過得鏈表直接反轉
        slow.next = prev
        prev = slow

        slow = temp // 慢指針走1個節點
    }
    if(fast){ // 奇數個節點的鏈表
        slow = slow.next
    }
    while(slow){
        if(slow.val !== prev.val) return false;

        slow = slow.next
        prev = prev.next
    }
    return true
};

鏈表經典問題

  1. 你可以同時使用多個指針。

    • 有時,當你爲鏈表問題設計算法時,可能需要同時跟蹤多個結點。
    • 您應該記住需要跟蹤哪些結點,並且可以自由地使用幾個不同的結點指針來同時跟蹤這些結點。
    • 如果你使用多個指針,最好爲它們指定適當的名稱,以防將來必須調試或檢查代碼。
  2. 在許多情況下,你需要跟蹤當前結點的前一個結點。

    • 你無法追溯單鏈表中的前一個結點。
    • 因此,您不僅要存儲當前結點,還要存儲前一個結點。

我們將在下一篇文章中談一談雙鏈表的基本原理,以及js的實戰

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章