面试经典算法9-反转链表Ⅱ
LeetCode.92
公众号:阿Q技术站
问题描述
给你单链表的头指针 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
思路
- 创建虚拟头节点:首先,创建一个虚拟头节点
dummy
,并将它的next
指针指向原始链表的头节点head
。这样做的目的是为了处理反转部分的特殊情况,例如需要反转的部分从链表的头部开始。 - 定位需要反转的部分:使用两个指针
pre
和cur
分别指向需要反转部分的前一个节点和第一个节点。通过遍历链表,将pre
移动到需要反转部分的前一个节点,将cur
移动到需要反转的第一个节点。 - 反转链表部分:接下来,使用头插法将需要反转的部分进行反转操作。具体步骤如下:
- 遍历需要反转的部分,每次取出当前节点
cur
的下一个节点next
。 - 将
cur
的next
指针指向next
的下一个节点,即断开next
节点。 - 将
next
的next
指针指向pre
的下一个节点,即将next
节点插入到pre
节点之后。 - 更新
pre
的next
指针,将其指向next
,完成节点的插入操作。
- 遍历需要反转的部分,每次取出当前节点
- 返回反转后的链表:最后,返回虚拟头节点
dummy
的next
指针,即为反转后的链表头节点。
图解
- 初始状态,head = [1,2,3,4,5], left = 2, right = 4
- 创建一个虚拟头节点,并初始化pre节点,cur节点。根据left确定pre和cur的位置。将
pre
移动到第一个要反转的节点的前面,将cur
移动到第一个要反转的节点的位置上。我们就以left=2
,right=4
为例。
- 将
cur
后面的元素删除,然后添加到pre
的后面,这里就跟反转链表的步骤一样了。
- 重复步骤3
- 返回反转后的链表头节点
参考代码
C++
#include <iostream>
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(nullptr) {}
};
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
if (left == right) {
return head; // 如果 left 和 right 相等,不需要反转,直接返回头节点
}
ListNode *dummy = new ListNode(0); // 创建一个虚拟头节点,方便处理头部的特殊情况
dummy->next = head;
ListNode *pre = dummy; // pre 指向需要反转部分的前一个节点
for (int i = 0; i < left - 1; ++i) {
pre = pre->next;
}
ListNode *cur = pre->next; // cur 指向需要反转的第一个节点
for (int i = 0; i < right - left; ++i) {
ListNode *next = cur->next; // 记录下一个节点
cur->next = next->next; // 将当前节点的 next 指针指向下一个节点的下一个节点,断开 next 节点
next->next = pre->next; // 将 next 节点插入到 pre 节点之后
pre->next = next; // 更新 pre 的 next 指针,连接反转部分
}
return dummy->next; // 返回反转后的链表头节点
}
};
void printList(ListNode *head) {
ListNode *cur = head;
while (cur != nullptr) {
std::cout << cur->val << " ";
cur = cur->next;
}
std::cout << std::endl;
}
int main() {
ListNode *head = new ListNode(1);
head->next = new ListNode(2);
head->next->next = new ListNode(3);
head->next->next->next = new ListNode(4);
head->next->next->next->next = new ListNode(5);
Solution solution;
ListNode *newHead = solution.reverseBetween(head, 2, 4);
printList(newHead); // 输出:1 4 3 2 5
return 0;
}
Java
class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
if (left == right) {
return head; // 如果 left 和 right 相等,不需要反转,直接返回头节点
}
ListNode dummy = new ListNode(0); // 创建一个虚拟头节点,方便处理头部的特殊情况
dummy.next = head;
ListNode prev = dummy; // prev 指向需要反转部分的前一个节点
for (int i = 0; i < left - 1; ++i) {
prev = prev.next;
}
ListNode curr = prev.next; // curr 指向需要反转的第一个节点
for (int i = 0; i < right - left; ++i) {
ListNode next = curr.next; // 记录下一个节点
curr.next = next.next; // 将当前节点的 next 指针指向下一个节点的下一个节点,断开 next 节点
next.next = prev.next; // 将 next 节点插入到 prev 节点之后
prev.next = next; // 更新 prev 的 next 指针,连接反转部分
}
return dummy.next; // 返回反转后的链表头节点
}
}
public class Main {
public static void main(String[] args) {
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
head.next.next.next = new ListNode(4);
head.next.next.next.next = new ListNode(5);
Solution solution = new Solution();
ListNode newHead = solution.reverseBetween(head, 2, 4);
printList(newHead); // 输出:1 4 3 2 5
}
private static void printList(ListNode head) {
ListNode curr = head;
while (curr != null) {
System.out.print(curr.val + " ");
curr = curr.next;
}
System.out.println();
}
}
Python
# 定义链表节点
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
if left == right:
return head # 如果 left 和 right 相等,不需要反转,直接返回头节点
dummy = ListNode(0) # 创建一个虚拟头节点,方便处理头部的特殊情况
dummy.next = head
prev = dummy # prev 指向需要反转部分的前一个节点
for _ in range(left - 1):
prev = prev.next
curr = prev.next # curr 指向需要反转的第一个节点
for _ in range(right - left):
next_node = curr.next # 记录下一个节点
curr.next = next_node.next # 将当前节点的 next 指针指向下一个节点的下一个节点,断开 next 节点
next_node.next = prev.next # 将 next 节点插入到 prev 节点之后
prev.next = next_node # 更新 prev 的 next 指针,连接反转部分
return dummy.next # 返回反转后的链表头节点
def printList(head: ListNode) -> None:
curr = head
while curr:
print(curr.val, end=" ")
curr = curr.next
print()
if __name__ == "__main__":
head = ListNode(1)
head.next = ListNode(2)
head.next.next = ListNode(3)
head.next.next.next = ListNode(4)
head.next.next.next.next = ListNode(5)
solution = Solution()
new_head = solution.reverseBetween(head, 2, 4)
printList(new_head) # 输出:1 4 3 2 5