@labuladong
因为边界条件纠结了一晚上,感觉想明白了,就做一下记录吧,实在太绕了。
不过也在力扣题解里看到了没我想的这么饶的,也贴在下面。
class Solution {
//找倒数n个结点
public ListNode findNthFromEnd(ListNode head , int k){
ListNode p1 = head;
for(int i = 0; i < k; i++){
p1 = p1.next;
}
ListNode p2 = head;
while(p1 != null){
p1 = p1.next;
p2 = p2.next;
}
return p2;//p2指向倒数 k 结点
}//此函数无需考虑虚拟头结点
public ListNode removeNthFromEnd(ListNode head, int n) {
//虚拟头结点的作用只是为了防止返回空指针,出现异常,如链中只有头结点一个元素,头结点会被删除
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode rem = findNthFromEnd(dummy,n+1);//即返回倒数 n+1 个结点
rem.next = rem.next.next;
return dummy.next;
}
/*当头结点就是第一个数时,从头结点到尾结点需要移动 n-1 次
从头结点到结点为null需要移动 n 次
所以需要移动 n 次,判断条件(p == null)成立,不再移动
移动 n-1 次,到达尾结点,判断条件(p.next == null)成立
p1移动 k 次,还需要移动 n-k 次到达判断条件(p == null)
p2则恰好需要移动 n-k 次到达倒数第 k 个结点
因为从 null 到倒数 k 个结点需要移动 k 次,则从头结点到倒数 k 个结点需要移动 n-k 次
*/
}
1.明确虚拟头结点的作用,并不影响结点个数以及需要移动的次数
2.需要移动的次数最好带真实的数去理解,或者结果不对的时候多试试?
当头结点就是第一个数时,从头结点到尾结点需要移动 n-1 次
从头结点到结点为null需要移动 n 次
所以需要移动 n 次,判断条件(p == null)成立,不再移动
移动 n-1 次,到达尾结点,判断条件(p.next == null)成立
p1移动 k 次,还需要移动 n-k 次到达判断条件(p == null)
p2则恰好需要移动 n-k 次到达倒数第 k 个结点
因为从 null 到倒数 k 个结点需要移动 k 次,则从头结点到倒数 k 个结点需要移动 n-k 次
另一种思路:
感觉也是直接带真数推一下比较快。