LeetCode 19: Remove Nth Node From End of List

LeetCode 19: Remove Nth Node From End of List

    • [1. Problem Link 🔗](#1. Problem Link 🔗)
    • [2. Solution Overview 🧭](#2. Solution Overview 🧭)
    • [3. Solution 1: Two Pointers with Dummy Node (Recommended)](#3. Solution 1: Two Pointers with Dummy Node (Recommended))
      • [3.1. Algorithm](#3.1. Algorithm)
      • [3.2. Important Points](#3.2. Important Points)
      • [3.3. Java Implementation](#3.3. Java Implementation)
      • [3.4. Time & Space Complexity](#3.4. Time & Space Complexity)
    • [4. Solution 2: Two Pass with Length Calculation](#4. Solution 2: Two Pass with Length Calculation)
      • [4.1. Algorithm思路](#4.1. Algorithm思路)
      • [4.2. Important Points](#4.2. Important Points)
      • [4.3. Java Implementation](#4.3. Java Implementation)
      • [4.4. Time & Space Complexity](#4.4. Time & Space Complexity)
    • [5. Solution 3: Recursive Approach](#5. Solution 3: Recursive Approach)
      • [5.1. Algorithm思路](#5.1. Algorithm思路)
      • [5.2. Important Points](#5.2. Important Points)
      • [5.3. Java Implementation](#5.3. Java Implementation)
      • [5.4. Time & Space Complexity](#5.4. Time & Space Complexity)
    • [6. Solution 4: Stack-based Approach](#6. Solution 4: Stack-based Approach)
      • [6.1. Algorithm思路](#6.1. Algorithm思路)
      • [6.2. Important Points](#6.2. Important Points)
      • [6.3. Java Implementation](#6.3. Java Implementation)
      • [6.4. Time & Space Complexity](#6.4. Time & Space Complexity)
    • [7. Solution 5: Two Pointers without Dummy Node](#7. Solution 5: Two Pointers without Dummy Node)
      • [7.1. Algorithm思路](#7.1. Algorithm思路)
      • [7.2. Important Points](#7.2. Important Points)
      • [7.3. Java Implementation](#7.3. Java Implementation)
      • [7.4. Time & Space Complexity](#7.4. Time & Space Complexity)
    • [8. Solution Comparison 📊](#8. Solution Comparison 📊)
    • [9. Summary 📝](#9. Summary 📝)

LeetCode 19: Remove Nth Node From End of List

2. Solution Overview 🧭

Given the head of a linked list, remove the nth node from the end of the list and return its head.

Example:

复制代码
Input: head = [1,2,3,4,5], n = 2
Output: [1,2,3,5]

Input: head = [1], n = 1
Output: []

Constraints:

  • The number of nodes in the list is sz
  • 1 <= sz <= 30
  • 0 <= Node.val <= 100
  • 1 <= n <= sz

Common approaches include:

  • Two Pass with Length Calculation: Calculate length first, then remove (L-n+1)th node
  • One Pass with Two Pointers: Use fast and slow pointers to find the nth node from end
  • Stack-based Approach: Use stack to track nodes (less efficient)

3. Solution 1: Two Pointers with Dummy Node (Recommended)

3.1. Algorithm

  • Use a dummy node to handle edge cases (like removing head)
  • Move fast pointer n steps ahead of slow pointer
  • Move both pointers until fast reaches the end
  • Slow pointer will be at (n+1)th node from end
  • Remove the next node of slow pointer

3.2. Important Points

  • Most efficient and elegant solution
  • Handles edge cases gracefully
  • One pass algorithm

3.3. Java Implementation

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) {
        // Create dummy node to handle edge cases
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        
        ListNode slow = dummy;
        ListNode fast = dummy;
        
        // Move fast pointer n steps ahead
        for (int i = 0; i < n; i++) {
            fast = fast.next;
        }
        
        // Move both pointers until fast reaches the end
        while (fast.next != null) {
            slow = slow.next;
            fast = fast.next;
        }
        
        // Remove the nth node from end
        slow.next = slow.next.next;
        
        return dummy.next;
    }
}

3.4. Time & Space Complexity

  • Time Complexity: O(L) where L is the length of the list
  • Space Complexity: O(1)

4. Solution 2: Two Pass with Length Calculation

4.1. Algorithm思路

  • First pass: Calculate the length of the list
  • Calculate which node to remove (length - n + 1)
  • Second pass: Traverse to the node before the target and remove it

4.2. Important Points

  • Simple and intuitive
  • Easy to understand and implement
  • Two passes but still efficient

4.3. Java Implementation

java 复制代码
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        // Calculate length of the list
        int length = 0;
        ListNode current = head;
        while (current != null) {
            length++;
            current = current.next;
        }
        
        // If removing the head
        if (n == length) {
            return head.next;
        }
        
        // Find the node before the one to remove
        current = head;
        for (int i = 1; i < length - n; i++) {
            current = current.next;
        }
        
        // Remove the node
        current.next = current.next.next;
        
        return head;
    }
}

4.4. Time & Space Complexity

  • Time Complexity: O(L)
  • Space Complexity: O(1)

5. Solution 3: Recursive Approach

5.1. Algorithm思路

  • Use recursion to traverse to the end of the list
  • Use a counter to track the position from the end
  • When counter equals n, skip that node

5.2. Important Points

  • Elegant recursive solution
  • Uses O(L) stack space
  • Good for understanding recursion

5.3. Java Implementation

java 复制代码
class Solution {
    private int count = 0;
    
    public ListNode removeNthFromEnd(ListNode head, int n) {
        // Use a dummy node to handle head removal
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        removeHelper(dummy, n);
        return dummy.next;
    }
    
    private void removeHelper(ListNode node, int n) {
        if (node == null) {
            return;
        }
        
        removeHelper(node.next, n);
        count++;
        
        // When we reach the nth node from end in backtracking
        if (count == n + 1) {
            node.next = node.next.next;
        }
    }
}

5.4. Time & Space Complexity

  • Time Complexity: O(L)
  • Space Complexity: O(L) for recursion stack

6. Solution 4: Stack-based Approach

6.1. Algorithm思路

  • Push all nodes onto a stack
  • Pop n nodes to reach the nth node from end
  • The next node in stack is the one before the target
  • Remove the target node

6.2. Important Points

  • Simple to understand
  • Uses O(L) extra space
  • Good for learning purposes

6.3. Java Implementation

java 复制代码
import java.util.Stack;

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        Stack<ListNode> stack = new Stack<>();
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode current = dummy;
        
        // Push all nodes onto stack
        while (current != null) {
            stack.push(current);
            current = current.next;
        }
        
        // Pop n nodes to find the node to remove
        for (int i = 0; i < n; i++) {
            stack.pop();
        }
        
        // The top of stack is the node before the target
        ListNode nodeBefore = stack.peek();
        nodeBefore.next = nodeBefore.next.next;
        
        return dummy.next;
    }
}

6.4. Time & Space Complexity

  • Time Complexity: O(L)
  • Space Complexity: O(L)

7. Solution 5: Two Pointers without Dummy Node

7.1. Algorithm思路

  • Similar to Solution 1 but without dummy node
  • Handle head removal as a special case
  • More complex edge case handling

7.2. Important Points

  • Saves one node of memory
  • More complex code
  • Good for understanding pointer manipulation

7.3. Java Implementation

java 复制代码
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode slow = head;
        ListNode fast = head;
        
        // Move fast pointer n steps ahead
        for (int i = 0; i < n; i++) {
            fast = fast.next;
        }
        
        // If fast is null, we're removing the head
        if (fast == null) {
            return head.next;
        }
        
        // Move both until fast reaches last node
        while (fast.next != null) {
            slow = slow.next;
            fast = fast.next;
        }
        
        // Remove the node
        slow.next = slow.next.next;
        
        return head;
    }
}

7.4. Time & Space Complexity

  • Time Complexity: O(L)
  • Space Complexity: O(1)

8. Solution Comparison 📊

Solution Time Complexity Space Complexity Advantages Disadvantages
Two Pointers with Dummy O(L) O(1) Elegant, handles edges well Uses one extra node
Two Pass with Length O(L) O(1) Simple, intuitive Two passes
Recursive O(L) O(L) Elegant, recursive thinking Stack overflow risk
Stack-based O(L) O(L) Easy to understand Extra space usage
Two Pointers without Dummy O(L) O(1) No extra node Complex edge handling

9. Summary 📝

  • Key Insight: The nth node from end is the (L-n+1)th node from beginning
  • Recommended Approach: Solution 1 (Two Pointers with Dummy Node) is most commonly used
  • Critical Technique: Using two pointers with n-step difference to find the target in one pass
  • Pattern Recognition: This is a classic two-pointer pattern for linked list problems

Why Two Pointers Work:

  • When fast pointer is n steps ahead, and both move at same speed
  • When fast reaches the end, slow will be at (L-n)th position
  • This allows us to remove the next node (which is the target)

The two pointers with dummy node approach is generally preferred for its elegance and robustness in handling edge cases.

相关推荐
文丑颜不良啊几秒前
LeetCode76~100题目解析
java·leetcode
她的男孩3 分钟前
页面已发布用户仍进不去:Forge Admin 门户入口与系统菜单挂载解耦
java·spring boot·低代码
不像程序员的程序媛7 分钟前
mybatisplus insert dto未指定id时会如何
java·开发语言
闻缺陷则喜何志丹13 分钟前
vc入门宝典(九)
数据结构·list·mfc·存储·null·class
零基础12324 分钟前
基于模型的强化学习与不基于模型的强化学习:核心区别与实战选择
python·算法
我命由我1234526 分钟前
5-2.Python 编码进阶 - 字符串进阶(拼接、普通格式化、普通格式化数字精度控制、快速格式化、遍历、常用方法)
java·开发语言·后端·python·学习·java-ee·学习方法
Pniubi8 小时前
HashMap的扩容和树化边界
java·开发语言
Mikko79 小时前
用 Java 复刻了高中时在塞班上玩的「熔岩矿车」:纯 Swing、零依赖、没有一张图片,一个 jar 双击就能玩
java·游戏开发·swing
知了学历孙老师9 小时前
小自考的校考和统考,出题方和难度差在哪
java·大数据·前端
Java爱好狂.9 小时前
Java初学者如何一周速通SpringBoot!
java·spring boot·后端·spring·高并发·架构师·java面试