鏈表高頻面試題、經典問題
關於我
- decs: 19年畢業的前端開發一枚,沉迷Js
- 花名: 餘光
- E-mail: [email protected]
- 個人博客: CSDN
- GitHub: 傳送門
經典問題
在閱讀了單鏈表原理和雙指針技技巧後,我們仍然在LeeCode上找出幾個經典面試題,以此加強掌握。
一、反轉鏈表
思路
我們接受到鏈表 [1, 2, 3, 4, 5]
-
首先,我們將head結點的下一個結點(即結點 2)移動到列表的頭部
pre
:
-
然後,我們將黑色結點的下一個結點(即結點 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
};
鏈表經典問題
-
你可以同時使用多個指針。
- 有時,當你爲鏈表問題設計算法時,可能需要同時跟蹤多個結點。
- 您應該記住需要跟蹤哪些結點,並且可以自由地使用幾個不同的結點指針來同時跟蹤這些結點。
- 如果你使用多個指針,最好爲它們指定適當的名稱,以防將來必須調試或檢查代碼。
-
在許多情況下,你需要跟蹤當前結點的前一個結點。
- 你無法追溯單鏈表中的前一個結點。
- 因此,您不僅要存儲當前結點,還要存儲前一個結點。
我們將在下一篇文章中談一談雙鏈表的基本原理,以及js的實戰