例如
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
输入:head = [1], n = 1
输出:[]
输入:head = [1,2], n = 1
输出:[1]
另外题目提示
-
链表至少一个节点
-
n 只会在合理范围
方法一
思路,写一个递归函数,用来返回下一个节点的倒数序号
recursion(ListNode p=1, int n=2) {
recursion(ListNode p=2, int n=2) {
recursion(ListNode p=3, int n=2) {
recursion(ListNode p=4, int n=2) {
recursion(ListNode p=5, int n=2) {
recursion(ListNode p=null, int n=2) {
return 0; // 最内层序号0
}
return 1; // 上一次返回值+1
}
return 2;
}
if(返回值 == n == 2) {
// 删除 next
}
return 3;
}
return 4;
}
return 5;
}
但上述代码有一个问题,就是若删除的是第一个节点,它没有上一个节点,因此可以加一个哨兵来解决
代码:
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode sentinel = new ListNode(-1, head);
recursion(sentinel, n);
return sentinel.next;
}
public int recursion(ListNode p, int n) {
if (p == null) {
return 0;
}
int nth = recursion(p.next, n);
if (nth == n) {
p.next = p.next.next;
}
return nth + 1;
}
Q:p.next.next 不怕空指针吗?
A:
p 是待删除节点的上一个节点,如果能递归回到 p,那么 p.next 肯定有值,不会是 null
且题目说明了 n >=1,不会因为 nth == 0 而让 p.next 指向最后的 null
方法二
快慢指针,p1 指向待删节点的上一个,p2 先走 n + 1 步
i=0
p2
s -> 1 -> 2 -> 3 -> 4 -> 5 -> null
i=1
p2
s -> 1 -> 2 -> 3 -> 4 -> 5 -> null
i=2
p2
s -> 1 -> 2 -> 3 -> 4 -> 5 -> null
i=3 从此开始 p1 p2 依次向右平移, 直到 p2 移动到末尾
p1 p2
s -> 1 -> 2 -> 3 -> 4 -> 5 -> null
p1 p2
s -> 1 -> 2 -> 3 -> 4 -> 5 -> null
代码:
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode s = new ListNode(-1, head);
ListNode p1 = s;
ListNode p2 = s;
for (int i = 0; i < n + 1; i++) {
p2 = p2.next;
}
while (p2 != null) {
p1 = p1.next;
p2 = p2.next;
}
p1.next = p1.next.next;
return s.next;
}
方法三
public ListNode removeNthFromEnd(ListNode head, int n) {
Composite c = recursion(head, n);
return c.node;
}
static class Composite {
ListNode node;
int nth;
public Composite(ListNode node, int nth) {
this.node = node;
this.nth = nth;
}
}
public Composite recursion(ListNode p, int n) {
if (p == null) {
return new Composite(null, 1);
}
Composite c = recursion(p.next, n);
if (c.nth != n) {
p.next = c.node;
c.node = p;
}
c.nth +=1;
return c;
}