题目

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

题解

思路1

dummyHead 和 双指针

fast 指针先走 n 步

接着 slow指针 和 fast指针一起走,直到fast指针走到最后

删除 slow指针所指节点

返回dummyHead.next , 不直接返回head ,因为可能删的就是head。

时间复杂度: O(N)- 空间复杂度: O(1)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */


public ListNode removeNthFromEnd(ListNode head, int n) {
    if (head == null)
        return head;

    ListNode dummy = new ListNode(-1);
    dummy.next = head;

    ListNode fast = dummy;
    ListNode slow = dummy;

    //fast 先走 n步
    for (int i = 0; i < n; i++) {
        fast = fast.next;
    }

    //slow 和 fast 一起走
    while (fast.next != null) {
        slow = slow.next;
        fast = fast.next;
    }

    //删除节点
    slow.next = slow.next.next;

    return dummy.next;
}

思路2

进阶:你能尝试使用一趟扫描实现吗?

在思路1的基础上用一个循环解决:

时间复杂度: O(N)- 空间复杂度: O(1)

public ListNode removeNthFromEnd(ListNode head, int n) {
    if (head == null)
        return head;

    ListNode dummy = new ListNode(-1);
    dummy.next = head;


    ListNode fast = dummy;
    ListNode slow = dummy;

    int count = 0;
    while (fast.next != null) {
        if (count < n) {
            count += 1;
            fast = fast.next;
        } else {
            slow = slow.next;
            fast = fast.next;
        }
    }

    //删除节点
    slow.next = slow.next.next;

    return dummy.next;
}