https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/

    1. 暴力法常规,倒数第N个,如果知道长度Len,那就是正数第Len - N + 1个。
    2. 多一趟完整遍历,时间复杂度太高。“一般”情况倒数多少个如果倒着数数量不会太多,如果借用“栈”数据结构,在全部入栈之后,倒着数几个就OK。
    3. 但是还是要一遍完整遍历+多几次,倒数第N个与末尾的距离,是不是可以利用下标0和下标N-1之间的距离表示,当N-1的那个指针遍历到末尾时,0那个指针遍历到目标位置。但是又是因为我们需要删除目标节点,所以要找到目标节点的前一个,方便删除。
    1. class Solution {
    2. public ListNode removeNthFromEnd(ListNode head, int n) {
    3. ListNode sentinel = new ListNode(-1, head);
    4. // 左右指针始终保持固定距离
    5. ListNode first = sentinel;
    6. ListNode second = sentinel;
    7. // 倒数 N + 1 个节点
    8. for (int i = 0; i < n + 1; i++) {
    9. first = first.next;
    10. }
    11. // first、second 同时移动
    12. while (first != null) {
    13. first = first.next;
    14. second = second.next;
    15. }
    16. second.next = second.next.next;
    17. return sentinel.next;
    18. }
    19. }
    1. class Solution {
    2. public ListNode removeNthFromEnd(ListNode head, int n) {
    3. ListNode sentinel = new ListNode(-1, head);
    4. ListNode cur = sentinel;
    5. // 定义一个栈
    6. Stack<ListNode> stack = new Stack<>();
    7. while (cur != null) {
    8. stack.push(cur);
    9. cur = cur.next;
    10. }
    11. // 弹栈
    12. for (int i = 0; i < n; i++) {
    13. stack.pop();
    14. }
    15. stack.peek().next = stack.peek().next.next;
    16. return sentinel.next;
    17. }
    18. }
    1. class Solution {
    2. public ListNode removeNthFromEnd(ListNode head, int n) {
    3. // 遍历链表得到长度
    4. int len = getLength(head);
    5. // 从前至后遍历,找到正数 len - n + 1 个元素
    6. // 定义哨兵
    7. ListNode sentinel = new ListNode(-1, head);
    8. ListNode cur = sentinel;
    9. for (int i = 0; i < len - n; i++) {
    10. cur = cur.next;
    11. }
    12. // 找到第 len - n 个节点
    13. cur.next = cur.next.next;
    14. return sentinel.next;
    15. }
    16. public static int getLength(ListNode head) {
    17. int length = 0;
    18. while (head != null) {
    19. length++;
    20. head = head.next;
    21. }
    22. return length;
    23. }
    24. }