反转链表 II
难度:
标签:
题目描述
给你单链表的头指针
head
和两个整数 left
和 right
,其中 left <= right
。请你反转从位置 left
到位置 right
的链表节点,返回 反转后的链表 。
示例 1:
输入:head = [1,2,3,4,5], left = 2, right = 4 输出:[1,4,3,2,5]
示例 2:
输入:head = [5], left = 1, right = 1 输出:[5]
提示:
- 链表中节点数目为
n
1 <= n <= 500
-500 <= Node.val <= 500
1 <= left <= right <= n
进阶: 你可以使用一趟扫描完成反转吗?
代码结果
运行时间: 28 ms, 内存: 15.1 MB
/*
* 思路:
* 1. 使用流来遍历链表。
* 2. 在链表的第left到right之间反转子链表。
* 3. 将反转后的链表重新链接。
*/
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
class ListNode {
int val;
ListNode next;
ListNode(int val) { this.val = val; }
}
public class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
if (head == null) return null;
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
for (int i = 0; i < left - 1; i++) {
pre = pre.next;
}
ListNode start = pre.next;
ListNode then = start.next;
for (int i = 0; i < right - left; i++) {
start.next = then.next;
then.next = pre.next;
pre.next = then;
then = start.next;
}
return dummy.next;
}
}
解释
方法:
题解的思路是先找到需要反转的子链表的起始节点和结束节点,然后将这一段子链表反转,最后将反转后的子链表重新连接到原链表中。具体步骤如下:
1. 创建一个虚拟头节点 dummy,指向原链表的头节点。
2. 定义两个指针 pre 和 a,初始时都指向 dummy。
3. 先将 pre 和 a 向右移动 left-1 次,使得 a 指向需要反转的子链表的前一个节点。
4. 定义指针 b,初始时指向 a,然后将 b 向右移动 right-left+1 次,使得 b 指向需要反转的子链表的后一个节点。
5. 调用 reverse 函数反转 a 和 b 之间的子链表。
6. 将反转后的子链表重新连接到原链表中,即将 pre.next 指向反转后的子链表头节点,将 a.next 指向 b。
7. 返回 dummy.next,即反转后的链表的头节点。
时间复杂度:
O(right)
空间复杂度:
O(1)
代码细节讲解
🦆
在函数reverse中,b指针是否包含在需要反转的链表部分内,还是它指向反转部分之后的第一个节点?
▷🦆
在遍历过程中移动指针pre和a,如果left为1,即从头节点开始反转,这种情况下pre和a的初始位置是否有影响?
▷🦆
函数reverse执行完成后,为什么a.next直接连接到b,而没有检查b是否为None,特别是当right等于链表长度时?
▷🦆
你是如何确保在反转链表的过程中不会丢失任何节点?具体是哪些操作保证了节点的完整性?
▷