import java.util.Stack;

public class RemoveNthEnd {
    //方法一:计算链表长度
    public ListNode removeNthFromEnd1(ListNode head, int n) {
        //1.遍历链表,得到长度l
        int l = getLength(head);
        ListNode result = null;
        //2.从前到后遍历,找到正数第l-n+1个元素
        //定义一个哨兵节点,next指向头节点
        ListNode sentinel = new ListNode(-1,head);
        ListNode curr = sentinel;
        for (int i = 0; i <l-n ; i++) {
            curr = curr.next;
        }
        //找到第l-n个节点

        //跳过第l-n+1个节点
        curr.next = curr.next.next;

        return sentinel.next;
    }

    //定义一个计算链表长度的方法
    public static int getLength(ListNode head){
        int length = 0;
        while (head!=null){
            length++;
            head = head.next;
        }
        return length;
    }
    //方法二:计算链表长度
    public ListNode removeNthFromEnd2(ListNode head, int n) {
        //定义一个哨兵节点,next指向头节点
        ListNode sentinel = new ListNode(-1,head);
        ListNode curr = sentinel;

        //定义一个栈
        Stack<ListNode> stack = new Stack<>();

        //1.将所有节点入栈
        while (curr!=null){
            stack.push(curr);
            curr = curr.next;
        }

        //2.弹栈n次
        for (int i = 0; i <n ; i++) {
            stack.pop();
        }

        //3.当前栈顶元素即为要删除元素
        stack.peek().next = stack.peek().next.next;

        return sentinel.next;
    }

    //方法三:双指针(一次遍历)
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //定义一个哨兵节点,next指向头节点
        ListNode sentinel = new ListNode(-1,head);

        //定义前后双指针
        ListNode first = sentinel;
        ListNode second = sentinel;

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

        //2.first,second同时前进,当first变为null时,second就说倒数第n+1个节点
        while (first!=null){
            first = first.next;
            second = second.next;
        }

        //3.删除倒是第n个节点
        second.next = second.next.next;

        return sentinel.next;
    }
    public static void main(String[] args) {
        ListNode listNode1 = new ListNode(1);
        ListNode listNode2 = new ListNode(2);
        ListNode listNode3 = new ListNode(3);
        ListNode listNode4 = new ListNode(4);
        ListNode listNode5 = new ListNode(5);

        listNode1.next = listNode2;
        listNode2.next = listNode3;
        listNode3.next = listNode4;
        listNode4.next = listNode5;
        listNode5.next = null;
        TestLinkedList.printList(listNode1);
        RemoveNthEnd removeNthEnd = new RemoveNthEnd();
        TestLinkedList.printList(removeNthEnd.removeNthFromEnd(listNode1,2));
    }
}