题目(难度:中等):
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
解法:
在求出链表长度len之后,利用(len-n)从头开始遍历,删除指定节点。
代码实现:
package Middle;
import java.util.Random;
/**
* Created by lizeyang on 2019/9/2.
*/
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
public class Solution6 {
private static int len=0;
public ListNode removeNthFromEnd(ListNode head,int n){
ListNode p = head,q=head.next,l=head;
int num=0;
while(p!=null){
len++;
System.out.print(p.val+" ");
p = p.next;
}
System.out.println();
if(n>len){
System.out.print("删除结点位置超出链表范围!");
System.exit(0); //退出程序
}
else{
int order = len-n;
if(order==0){ //删除的是头节点
l=l.next;
if(l==null){ //删除的是头节点且该链表只有一个元素
return null;
}
return l;
}
while(num<order-1){
head=head.next;
q=q.next;
num++;
}
head.next=q.next;
}
return l;
}
public static void main(String[] args){
ListNode head =null;
Random rand = new Random(12);
for(int i=0;i<1;i++){
ListNode newnode = new ListNode(rand.nextInt(10)+1);
newnode.next = head;
head=newnode;
}
Solution6 solution6 = new Solution6();
ListNode l = solution6.removeNthFromEnd(head,1);
while(l!=null){
System.out.print(l.val+" ");
l=l.next;
}
}
}
运行结果:(删除倒数第2个节点)
缺陷:
未能实现一遍遍历删除节点
改进:
我们可以设想假设设定了双指针p
和q
的话,当q
指向末尾的NULL
,p
与q
之间相隔的元素个数为n
时,那么删除掉p
的下一个指针就完成了要求。
- 设置虚拟节点
dummyHead
指向head
- 设定双指针
p
和q
,初始都指向虚拟节点dummyHead
- 移动
q
,直到p
与q
之间相隔的元素个数为n
- 同时移动
p
与q
,直到q
指向的为NULL
- 将
p
的下一个节点指向下下个节点
代码实现:
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
ListNode p = dummyNode, q = dummyNode;
for (int i = 0; i < n + 1; i++) {
q = q.next;
}
while (q != null) {
p = p.next;
q = q.next;
}
ListNode del = p.next;
p.next = del.next;
return dummyNode.next;
}
算法实现:
时间复杂度O(n),额外空间复杂度O(1)