题目
思路
遍历两遍链表
常规方法,将删掉倒数第N个节点变为删除正数第long-n+1个节点。由于链表的长度只能对其遍历后得到,因此该方法需要遍历两遍链表。第一遍得到链表的总长度,用于计算删除的节点是正序中的第几个节点,第二遍遍历到该节点进行删除操作。
只遍历一遍链表
使用两个指针,两指针之间间隔n-1个节点,这样当后面那个指针到达链表的终点时,前一个指针所指位置恰好是需要删除的节点位置。我自己写的时候,还用了一个指针来存放前面那个指针的前一个位置,用于删除节点,看了以下题解,可以将前一个指针直接指向需要删除节点的前节点,进行删除。
代码
public ListNode removeNthFromEnd_1(ListNode head, int n) {
// 倒数第n个节点 == 正序第(链表长度 - n + 1)
// 链表长度需要先遍历一遍后才能知道
int count = 0;
ListNode cur = head;
while (cur != null){
count += 1;
cur = cur.next;
}
// System.out.println("链表长度为:"+count);
// 删掉正数第 count-n+1个节点
ListNode pre_head = new ListNode(-1);//虚拟头节点
pre_head.next = head;
int temp = 1;
ListNode pre = pre_head;//记录前节点
ListNode q = head;
while (temp <= count - n){
pre = q;
q = q.next;
temp += 1;
}
pre.next = q.next;//删除p结点
return pre_head.next;
}
public ListNode removeNthFromEnd_2(ListNode head, int n) {
// 初始化p指针指向q的前n-1个 然后q遍历到最后一个结点时 p指向的结点就是需要删除的结点
ListNode p = new ListNode();
ListNode q = new ListNode();
ListNode pre_head = new ListNode();
pre_head.next = head;
//初始化指针的位置
int count = 0;
q = head;
p = head;
ListNode pre_p = pre_head;
while (count < n-1){
q = q.next;
count += 1;
}
//p,q同时向后移动,直到q遍历到最后一个结点
while (q.next != null){
pre_p = p;
p = p.next;
q = q.next;
}
//此时p所指向的结点就是需要删除的结点
pre_p.next = p.next;
return pre_head.next;
}