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直接指向第一个有效元素。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。