Problem: 19. 删除链表的倒数第 N 个结点
思路1
计算链表长度。
因为删除的是倒数的第 N 个结点,只要把正数的节点位置算出来,删除节点即可。
解题方法1
步骤1:计算正数的位置、 链表只能从头节点开始遍历,要找到正数节点的位置,我们只需要: 链表的长度 - 倒数节点的位置 + 1
这里需要注意,我们要找的位置是删除节点的前一个位置,而不是要删除节点的位置。
步骤2: 删除节点 将要删除的节点的前驱指向它的下下一个节点。
注意:这里我们使用了添加哑节点(dummy node)的技巧, 它的 next 指针指向链表的头节点,这时候就不需要对头节点进行特殊的判断了。
复杂度1
- 时间复杂度:
, L 为链表长度
- 空间复杂度:
Code1
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var getLength = function(head) {
let n = 0;
while(head) {
n++;
head = head.next;
}
return n;
}
var removeNthFromEnd = function(head, n) {
const length = getLength(head);
const preIndex = length - n + 1;
const dummy = new ListNode(0);
dummy.next = head;
let cur = dummy;
for(let i = 1; i < preIndex; i++) {
cur = cur.next;
}
cur.next = cur.next.next;
return dummy.next;
};
思路2
双指针 使用两个指针,first 和 second,first 指针让它先走 N 步,然后两个指针一起走,first 指针走到链表结束位置,此时 second 指针恰好就是在要删除的节点。当我们希望得到要删除节点的前驱节点,可以在初始时将 second 节点指向哑节点。
复杂度2
- 时间复杂度:
, L 为链表长度
- 空间复杂度:
Code2
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
const dummy = new ListNode(0);
dummy.next = head;
let first = head, second = dummy;
for (let i = 0; i < n; ++i) {
first = first.next;
}
while(first) {
first = first.next;
second = second.next;
}
second.next = second.next.next;
return dummy.next;
};
参考: 删除链表的倒数第N个节点