当前位置 博文首页 > 龚厂长的博客:leetcode-31. 下一个排列
题目:
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
分析:
不考虑进阶要求的话,这个题目很简单,要找倒数第n个节点,首先遍历一遍,找到链表的总长度length,然后length-n+1就是从链表头开始数要删除的节点了。然后再从头开始遍历找到length-n+1的节点删除即可。
下面考虑一下进阶,使用一趟扫描。
一趟扫描的话,我们考虑如下两个指针,一个指针用于遍历整个链表,另一个指针在遍历链表的过程中使用与第一个指针保持距离为n,也就是两者之间始终保持有n-1个节点,这样当第一个节点遍历到链表尾的时候,第二个指针指的位置正好是倒数第n个节点。这样使用一遍遍历便可以找到要删除的第n个节点了,但是还有一个问题,要删除第n个节点,需要知道这个节点的前一个节点,因此可以增加第三个指针,这个指针始终指向第二个指针指向的节点的前一个节点。
上面这个算法使用了三个指针,那么使用两个指针是否可行?答案是可行的,第一个指针还是用于遍历整个链表,第二个指针指向的节点始终与第一个指针指向的节点之间保存n个节点,这样第一个指针遍历到链表尾的时候,第二个指针指向的节点正是要删除节点的前一个节点。
代码如下:
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode preNthNode=null;//倒数第n节点的前一个节点
ListNode t=head;//遍历指针,用于遍历一遍链表
while(t.next!=null){
t=t.next;//切换下一个节点
n--;
if(n==0){
preNthNode=head;
}else if(n<0){
preNthNode=preNthNode.next;
}
}
//如果preNthNode=null,表示要删除的是链表的第一个节点
if(preNthNode==null){
head=head.next;//删除第一个节点
}else{
preNthNode.next=preNthNode.next.next;
}
return head;
}
运行结果: