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));
}
}