解法一:一次遍历+数组存储

用数组存储遍历过的点,根据索引得到第N个结点和它的前驱结点,然后进行删除操作。注意考虑边界情况。

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode() {}
  7. * ListNode(int val) { this.val = val; }
  8. * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
  9. * }
  10. */
  11. class Solution {
  12. public ListNode removeNthFromEnd(ListNode head, int n) {
  13. if (head == null) {
  14. return head;
  15. }
  16. List<ListNode> list = new ArrayList<>(n);
  17. ListNode p = head;
  18. while (p != null) {
  19. list.add(p);
  20. p = p.next;
  21. }
  22. if (list.size() > n) {
  23. ListNode toDeleteNode = list.get(list.size() - n);
  24. ListNode preNode = list.get(list.size() - n - 1);
  25. preNode.next = toDeleteNode.next;
  26. toDeleteNode = null;
  27. } else {
  28. p = head;
  29. head = head.next;
  30. p = null;
  31. }
  32. return head;
  33. }
  34. }

解法二:一次遍历+快慢指针

在第一个结点前面再创建一个头指针,作为慢指针的出发点,快指针以第一个结点为出发点,先走 n 步,然后慢指针和快指针一起遍历。这样,当快指针走到终点时,慢指针位于倒数第 N 个结点的前驱。

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode() {}
  7. * ListNode(int val) { this.val = val; }
  8. * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
  9. * }
  10. */
  11. class Solution {
  12. public ListNode removeNthFromEnd(ListNode head, int n) {
  13. if ((head == null) || (head.next == null)) {
  14. return null;
  15. }
  16. ListNode fast = head;
  17. ListNode slow = new ListNode(0, head);
  18. head = slow;
  19. for (int i = 0; i < n; ++i) {
  20. fast = fast.next;
  21. }
  22. while (fast != null) {
  23. fast = fast.next;
  24. slow = slow.next;
  25. }
  26. slow.next = slow.next.next;
  27. return head.next;
  28. }
  29. }