学习目标:
本次学习目标为 力扣初级算法-链表,其中主要的LC如下:
- 删除链表的倒数第N个节点
学习内容:
- 删除链表的倒数第N个节点 -----(链接)
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]示例2:
输入:head = [1], n = 1
输出:[]示例3:
输入:head = [1,2], n = 1
输出:[1]说明:
链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
解题思路:
-
解法一: 常规解法
-
边界问题:删除位大于入参的链表的长度 或者直接删除首结点的情况
-
代码逻辑过程:
- 声明 pre 变量作为需要删除的前一个结点
- 然后循环算出当前链表的长度 length
- 判断链表长度 length 与入参n 的关系,当 n > length 时,直接返回 入参head (相当于不做删除)
- 定位需要删除的节点位置-- 删除的节点位 last 等于 length - n,(这里解释下,正常下 last + n = length,此时做等式变换,即可知道我们需要删除的节点位 last = length - n)
- 接下来是替换删除位,将删除节点的上一个节点的 next 指向 删除节点的next。
-
代码实现:
/***
* 解法一 常规解法
*/
public ListNode removeNthFromEnd01(ListNode head, int n) {
// 边界条件: 删除位大于入参的链表的长度 或者直接删除首结点的情况
// 作为要删除结点的前一个结点
ListNode pre = head;
// 先循环算出链表的长度
int length = getLength(head);
if (n > length){
return head;
}
// 要删结点
int last = length - n;
if (0 == last){
return head.next;
}
// 循环遍历需要删除的节点对象
for (int i = 0; i < last - 1 ; i++) {
pre =pre.next;
}
// 将删除节点的前节点的 next 指向删除节点的下一节点
pre.next = pre.next.next;
return head;
}
private int getLength(ListNode head) {
int len = 0;
while (head != null) {
len++;
head = head.next;
}
return len;
}
解题思路:
-
解法二: 双指针解法
-
边界问题:删除位大于入参的链表的长度 或者直接删除首结点的情况
-
代码逻辑过程:
- 声明两个指针,分别作为 快、慢指针对应的节点: fastNode 、 slowNode
- 基于删除位 last 与 入参的倒数数 n 的关系,我们可以知道 last + n = length,但是当前解法不依赖于链表长度,故我们可以先循环 入参 n 次查找 fastNode 的next,将 fastNode 往后移动,当 fastNode 一直往后移动到 fastNode 不为 null 的情况,相当于遍历得到了 入参 head 的链表长度了,此时,在遍历到 n 点后, slowNode 慢指针节点也可是 slowNode = slowNode.next,slowNode 也就相当于 要删除的节点位 last 了。
-
代码实现:
/***
* 解法二: 双指针解法
*/
public ListNode removeNthFromEnd02(ListNode head, int n) {
ListNode fastNode = head ;
ListNode slowNode = head;
// 边界条件: 删除位大于入参的链表的长度 或者直接删除首结点的情况
for (int i = 0; i < n; i++) {
fastNode = fastNode.next;
}
// 如果遍历 n次后返回的是null,则 n已大于 链表的长度
if (null == fastNode ){
return head.next;
}
// 由于前面 fast 已迁移至第N位, 则需要删除的位置是 length - n ,此时通过 慢指针 slowNode 前移
// slowNode 到的点,即为要删除的链表节点
while (null != fastNode ){
fastNode = fastNode.next;
slowNode = slowNode.next;
}
slowNode.next = slowNode.next.next;
return head;
}
private int getLength(ListNode head) {
int len = 0;
while (head != null) {
len++;
head = head.next;
}
return len;
}