【题目一】链表的中间结点
给定一个头结点为
head
的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5] 输出:此列表中的结点 3 (序列化形式:[3,4,5]) 返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。 注意,我们返回了一个 ListNode 类型的对象 ans,这样: ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.示例 2:
输入:[1,2,3,4,5,6] 输出:此列表中的结点 4 (序列化形式:[4,5,6]) 由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。提示:
- 给定链表的结点数介于
1
和100
之间。
解法一:单指针法
思路:
1.第一次遍历整个链表,得到结点数
2.不难发现,不论是奇数的链表还是偶数的链表,只要从头走 结点数/2 就能找到中间结点
3.返回中间节点的结构体
代码实现:
class Solution {
public ListNode middleNode(ListNode head) {
ListNode a = head;
int count = 0;
while(a != null) {
a = a.next;
count++;
}
a = head;
for(int i = 0;i < count/2;i++) {
a = a.next;
}
return a;
}
}
解法二:快慢指针法
思路:让low指针走一步,fast走两步,当fast到达最后一个结点时,low指针一定指向中间结点
代码实现:
class Solution {
public ListNode middleNode(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}
【题目二】删除链表的倒数第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
进阶:你能尝试使用一趟扫描实现吗?
解法一:计算链表长度
思路:
1.先从头到尾遍历一次链表,得到链表长度 count
2.如果链表结点只有一个,直接返回null
3.找到第count - n - 1的结点,修改它的next为指向下下个结点
代码实现:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode a = head, b = head;
int count = 0;
while (a != null) {
a = a.next;
count++;
}
if (count == 1) {
return null;
}
if (count == n) {
head = head.next;
} else {
for (int i = 0; i < count - n - 1; i++) {
b = b.next;
}
b.next = b.next.next;
}
return head;
}
}
解法二:双指针
思路:
由于我们需要找到倒数第 n 个节点,因此我们可以使用两个指针同时对链表进行遍历,并且first比second超前 n 个节点。当 first 遍历到链表的末尾时,second 就恰好处于倒数第 n个节点。
具体地,初始时 first 和 second 均指向头节点。我们首先使用first 对链表进行遍历,遍历的次数为 n。此时first 和 second 之间间隔了n−1 个节点,即first 比second 超前了 n 个节点。
在这之后,我们同时使用first 和second 对链表进行遍历。当first 遍历到链表的末尾(即 first 为空指针)时,second 恰好指向倒数第 n 个节点。
因此我们可以考虑在初始时将 second 指向虚拟节点,其余的操作步骤不变。这样一来,当 first 遍历到链表的末尾时,second 的下一个节点就是我们需要删除的节点。
代码实现:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0, head);
ListNode first = head;
ListNode second = dummy;
for (int i = 0; i < n; ++i) {
first = first.next;
}
while (first != null) {
first = first.next;
second = second.next;
}
second.next = second.next.next;
ListNode ans = dummy.next;
return ans;
}
}
注:解法二来自力扣官方题解