学习来自《代码随想录》
双指针的操作,要注意,删除第N个节点,那么我们当前遍历的指针一定要指向 第N个节点的前一个节点,建议先看视频。
题目链接/文章讲解/视频讲解:代码随想录
题目:力扣题目链接
19 删除链表倒数第n个节点(快慢双指针法)
题目描述
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
示例
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]
输入:head = [1], n = 1 输出:[]
输入:head = [1,2], n = 1 输出:[1]
题解
思路
双指针法的经典应用,如果要删除倒数第n个节点,就要先找到这个节点,采用快慢指针的方法。最初快慢指针都指向头结点,快指针先走n步,然后快慢指针一起向前走,直到快指针走到null节点,此时慢指针就指向了倒数第n个节点。
以上为初始思路,但是会存在两个问题
1、当删除节点是头节点时,需要单独处理
2、如果fast先走n步,slow虽然找到了要删除的节点,但是删除操作要从该节点的上一个节点进行删除操作,此时已经丢失了上一个节点。
优化后:
1、引入虚拟头节点,在原头节点前加一个节点,统一代码逻辑。slow和fast初始化都为虚拟头节点。
2、为了slow最后指向的是倒数第N个节点的前一个节点,便于删除操作,fast要先走n+1步。
代码
java版本
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyHead = new ListNode(0,head);
ListNode slow = dummyHead;
ListNode fast = dummyHead;
//fast先走n+1 步
while(n>-1){
fast = fast.next;
n--;
}
//slow 和 fast 一起走,直到fast=null,此时slow指向要删除元素的上一个节点
while(fast != null){
slow = slow.next;
fast = fast.next;
}
slow.next = slow.next.next;
return dummyHead.next;
}
}
复杂度分析
时间复杂度:O(n)
空间复杂度:O(1)
python 版本
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummyHead = ListNode(0,head)
slow = dummyHead
fast = dummyHead
while n >- 1:
fast = fast.next
n -= 1
while fast != None:
slow = slow.next
fast = fast.next
slow.next = slow.next.next
return dummyHead.next