题目
https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
示例
输入: head = [1,2,3,4,5], n = 2
输出: [1,2,3,5]
输入: head = [1], n = 1
输出: []
解题思路
删除第 N 个节点很简单,找到第 N - 1 个节点,让他的 next 指向他 next 的 next即可,current.next = current.next.next
。
所以这题的关键点在于 如何找到一个链表的倒数第 N 个节点。
找到链表的第 N 个节点很简单,从头遍历即可,找倒数第 N 个结点也不复杂,如果知道了链表的长度 length,就可以转换为招链表的第 length - N 个节点了。
所以这一题可以先遍历一边链表,得到长度,再遍历第二遍,找到第 N - 1个节点即可,但这样需要两次遍历,显然不够优雅。
换个思路,仔细观察一下链表,目标节点到链表结尾的距离为 N ,那我们找到正数距离为 N 的位置,记为 fast,头节点记为 slow,他们之间的距离 为 N,那么当他们同时往后遍历,并且 fast 遍历到结尾时,slow 正好是目标位置,没错,就是 双指针。
这里我们按照上面思路封装一个方法,用来获取链表的倒数第 N 个节点,以后有需求可以直接拿来用。
const findLastN = (list, n) => {
let fast = list;
let slow = list;
let count = 0;
while(fast) {
if (count >= n) {
slow = slow.next;
}
count++;
fast = fast.next;
}
return slow;
}
不过本题还要考虑一个特殊情况:删除头节点。按照解题思路,我们需要获取倒数第 N + 1 个节点,而头节点的前面没有节点了,所以解法也很简单,给头节点的前面再添加一个节点(定义为 dummy)即可,操作的时候使用 dummy,最终返回 dummy.next
即可。
代码
/**
* 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 findLastN = (list, n) => {
let fast = list;
let slow = list;
let count = 0;
while(fast) {
if (count >= n) {
slow = slow.next;
}
count++;
fast = fast.next;
}
return slow;
}
const dummy = new ListNode(0, head);
const preN = findLastN(dummy, n + 1);
preN.next = preN.next.next;
return dummy.next;
};