题目
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
解题思路
链表的next
指向下一个节点,如果我们需要删除链表中的倒数第n
个节点,我们需要知道的是倒数第n+1
个节点,删除n+1
个节点后继节点后,连接剩余部分即可。
假设链表长度为length
,我们需要找到length-n-1
这个节点,所以思路转变到丈量链表长度,再根据长度确定第二次的循环次数。
解法一 两次循环
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
// 设置长度计数器
var count = 0;
// 初始化链表
var tempList = new ListNode(0)
// 链表指针指向待遍历链表
tempList.next = head
// 初始化指针
var first = head
// 遍历原链表获得长度 count
while(first != null){
count ++;
first = first.next
}
// 设置第二次遍历长度
count = count - n;
// 重制指针
first = tempList
// 避免链表节点为1 作出判断,并根据第二次遍历长度,找到 count-n-1 节点位置
while(count > 0){
first = first.next
count --
}
// 将 count - n 节点删除
first.next = first.next.next;
// 返回删除之后的链表
return tempList.next
};
解法一虽然简单易懂,但是并没有做到题目中所说的,利用一趟扫描完成。
这时候我们就应该思考,能够在一次遍历中,确定链表长度,并且确定链表长度-n的节点的方法。此时我们就不能使用单指针,而是使用双指针来完成了。
解法二 快慢指针
我们可以使用快慢指针在一次遍历中,找到要删除的节点的前一个节点。快指针从列表的前 n+1
处开始移动,同时慢指针从开头处开始移动,当快指针移动到链表的末尾时,慢指针移动到的位置,恰好是链表长度-n-1处。
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
var tempList = new ListNode(0)
tempList.next = head
// 创建快慢两个指针
var fast = tempList
var slow = tempList
// 快指针先行,走n步
while (n) {
fast = fast.next
n--
}
// 快指针和慢指针同时前进 当快指针到链表末端时,慢指针恰好运动到
while (fast.next) {
fast = fast.next
slow = slow.next
}
slow.next = slow.next.next
return tempList.next
}