力扣 https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/solution/shan-chu-lian-biao-de-dao-shu-di-nge-jie-dian-b-61/
https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/solution/shan-chu-lian-biao-de-dao-shu-di-nge-jie-dian-b-61/
方法一:暴力集合
- 耗费空间,不是本题的本意
package com.company.linked;
import java.util.ArrayList;
import java.util.List;
public class Solution4_1 {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode p = head;
        List<ListNode> nodeList = new ArrayList<>();
        while (p != null) {
            nodeList.add(p);
            p = p.next;
        }
        for (int i = nodeList.size() - 1; i >= 0; i--) {
            if (n + i == nodeList.size()) {
                if (i == 0) {
                    head = head.next;
                    return head;
                }
                ListNode pre = nodeList.get(i - 1);
                ListNode cur = nodeList.get(i);
                pre.next = cur.next;
                return head;
            }
        }
        return head;
    }
}
方法二:用队列,或栈
- 核心思想是只存储优先个的元素,相比方法一空间有节约
- 算是一个改良版本
- 不是题目的本意
package com.company.linked;
import java.util.ArrayDeque;
import java.util.Deque;
public class Solution4_2 {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode p = head;
        Deque<ListNode> nodeDeque = new ArrayDeque<>();
        while (p != null) {
            nodeDeque.offerLast(p);
            p = p.next;
            if (nodeDeque.size() > n + 1) {
                nodeDeque.removeFirst();
            }
        }
        if (nodeDeque.size() == 1 && nodeDeque.poll() == head) {
            return null;
        }
        if (nodeDeque.size() == n && nodeDeque.poll() == head) {
            head = head.next;
            return head;
        }
        ListNode pre = nodeDeque.getFirst();
        ListNode cur = pre.next;
        if (cur != null) {
            pre.next = cur.next;
        }
        return head;
    }
}
方法三:先计算对队列的长度
- 最多需要遍历两趟
- 也不是题目的本意
package com.company.linked;
public class Solution4_3 {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode p = head;
        int count = 0;
        while (p != null) {
            count++;
            p = p.next;
        }
        if (count == n) {
            head = head.next;
            return head;
        }
        p = head;
        for (int i = 1; i <= count; i++) {
            if (i + n == count) {
                ListNode cur = p.next;
                if (cur != null) {
                    p.next = cur.next;
                    return head;
                }
            }
            p = p.next;
        }
        return head;
    }
}
方法四:双指针
- 快慢指针移动
- 快慢指针的速度差就是 倒数第K个的K
- 快慢指针类似栈和队列的思路,只是用指针模拟了滑动窗口,节省空间
- 本题考点就是此
package com.company.linked;
public class Solution4_4 {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //哨兵指针:值为0,next执行head
        ListNode dummy = new ListNode(0, head);
        ListNode first = head;
        ListNode second = dummy;
        //快慢指针拉开距离 n
        for (int i = 0; i < n; ++i) {
            first = first.next;
        }
        while (first != null) {
            first = first.next;
            second = second.next;
        }
        second.next = second.next.next;
        ListNode ans = dummy.next;
        return ans;
    }
}










