给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。进阶:你能尝试使用一趟扫描实现吗?输入:head = [1,2,3,4,5], n = 2输出:[1,2,3,5]
如果只做一次扫描解不出来。不管用双指针还是栈都不止遍历一次。采用栈的方式,思路很好理解,就是对链表做一次遍历并入栈,然后做出栈,找到第n个栈元素,则该节点即为需要删除的节点。需要用一个额外的栈来存储。一种思路就是双指针,在对链表进行操作时,一般都先在链表的头部维护一个虚拟节点。双指针算法中需要先对链表遍历n个元素找到对应的节点定义为为right,然后再维护一个从左边元素开始的指针定义为左节点left,left和right节点同时向右遍历,当右边的指针到达链表尾部时即right.next=null时,则左指针指向的元素即为需要删除的元素。
其实两种方式算法复杂度都差不多,只不过采用栈的模式需要占用的内存空间要大写,但在力扣提交之后,算法运行效率差异还有点大。
package likouhot;
import java.util.Stack;
import leecodeOff.ListNode;
/*
* 19.删除链表的倒数第N个节点
*/
public class Demo19 {
/*
* 击败了10%的算法
*/
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head == null) {
return head;
}
Stack<ListNode> stack = new Stack<ListNode>();
ListNode p1 = head;
while(p1!=null) {
stack.push(p1);
p1 = p1.next;
}
ListNode pre = null;
ListNode cur = null;
while(n>0) {
cur = stack.pop();
n--;
}
if(stack.isEmpty()) {
return cur.next;
}
pre = stack.pop();
pre.next = cur.next;
return head;
}
//击败100%的算法
public ListNode removeNthFromEndNew(ListNode head, int n) {
ListNode dumpNode = new ListNode(0);
dumpNode.next = head;
//第一步找到间隔n的那个节点
ListNode right = dumpNode;
for(int i=0;i<n;i++) {
right = right.next;
}
ListNode left = dumpNode;
while(right!=null) {
right =right.next;
left = right==null?left:left.next;
}
left.next = left.next.next;
return dumpNode.next;
}
public static void main(String args[]) {
Demo19 demo = new Demo19();
ListNode node1 = new ListNode(1);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(3);
ListNode node4 = new ListNode(4);
ListNode node5 = new ListNode(5);
/*node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;*/
//ListNode value = demo.removeNthFromEnd(node1, 2);
ListNode value11 = demo.removeNthFromEndNew(node1, 1);
/*while(value!=null) {
System.out.println(value.val);
value = value.next;
}*/
System.out.println();
while(value11!=null) {
System.out.println(value11.val);
value11 = value11.next;
}
}
}