leetcode第19題
Given a linked list, remove the n-th node from the end of list and return its head.
給定一個連結串列,刪除連結串列的倒數第 n 個節點,並且返回連結串列的頭結點。
題中的坑
這個題要注意的是:網站定義的連結串列結構head指向第一個有效元素,沒有純正意義上的頭結點,我前兩次提交就是因為這個問題沒過。因為,若有一個真正的頭結點,則所有的元素處理方式都一樣。但以第一個有效元素為頭結點,就導致演算法的不一致,需要單獨處理第一個有效元素(頭結點)。
題目的額外限制
Could you do this in one pass?
你能嘗試使用一趟掃描實現嗎?
還好,題目約束,給定n值一定會是有效的(Given n will always be valid.),這可以少寫好多的邊界判斷。
我的解答(javascript)
思路
n值一定有效,又限定在一趟掃描過程中完成,那就是要在掃描的過程中,儲存刪除操作的所有資訊。很容易想到,連結串列的長度一定大於n,我們迭代處理的是當前元素,故只需要記住當前元素往前的第n+1個元素(即被刪除元素的前一個)就可以了。
連結結點定義
function ListNode(val) {
this.val = val
this.next = null;
}
單連結生成器(用於本地測試)
function build(arr) {
if(arr.length === 0) //注意:leetcode的空連結串列邏輯是head=null
return null
let rs = new ListNode(arr[0])
let head = rs
for(let i = 1; i < arr.length; i++) {
let newOne = new ListNode(arr[i])
rs.next = newOne
rs = newOne
}
return head
}
本地測試程式碼
let rs = removeNthFromEnd(build([1,2,3,4,5]), 2)
let cur = rs
let str = ``
while(cur !== null) {
str += `${cur.val} ${cur.next ? `->` : ``} `
cur = cur.next
}
console.log(str)
解答演算法
var removeNthFromEnd = function(head, n) {
let cur = head //迭代處理當前元素
let m = 0 //偏移量,用來指示要刪除的元素
let del = head //要刪除的元素
while (cur !== null) {
if(m > n) { //達到並偏移指示視窗
del = del.next
} else {
m++
}
cur = cur.next
}
if (del === head && m === n) //注意,刪除頭元素與其它元素是不一樣的
head = head.next //測試用例:[1] 1; [1,2] 2
else
del.next = del.next.next
return head
};
leetcode提交結果
Runtime: 56 ms, faster than 100.00% of JavaScript online submissions for Remove Nth Node From End of List.
我的第一個執行速度超過所有提交者的解答,^_^
完整程式碼
https://github.com/zhoutk/leetcode/blob/master/javascript/qs019_removeNthFromEnd_1.js
小結
本文主要標記leetcode中的連結串列結構的特殊性,head直接指向第一個有效元素。