链表内指定区间反转
题目
描述
将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)。
例如:
给出的链表为 1→2→3→4→5→NULL1→2→3→4→5→NUL**L, m=2,n=4m=2,n=4,
返回 1→4→3→2→5→NULL1→4→3→2→5→NUL**L.
数据范围: 链表长度 0<size≤10000<siz**e≤1000,0<m≤n≤size0<m≤n≤siz**e,链表中每个节点的值满足 ∣val∣≤1000∣val∣≤1000
要求:时间复杂度 O(n)O(n) ,空间复杂度 O(n)O(n)
进阶:时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)
示例1
输入:
{1,2,3,4,5},2,4
返回值:
{1,4,3,2,5}
示例2
输入:
{5},1,1
返回值:
{5}
算法思路
具体算法思路可以参考这位UP主的讲解
【玩转校招算法面试】第二天:链表内指定区间反转(动画演示、手写 Java 代码、详细注释、LeetCode 高频算法题)_哔哩哔哩_bilibili
要反转链表中从位置 m
到 n
之间的节点,我们可以按照以下步骤进行操作:
- 找到第
m-1
个节点:这个节点将成为反转部分的前一个节点。 - 找到第
n+1
个节点:这个节点将成为反转部分的后一个节点。 - 反转从第
m
个节点到第n
个节点之间的部分。 - 将反转部分的前一个节点指向反转后的新头节点。
- 将反转部分的新尾节点指向第
n+1
个节点。
具体步骤:
-
初始化指针:
prev
:指向第m-1
个节点(初始为NULL
)。curr
:指向第m
个节点。next
:用于保存curr
的下一个节点。
-
找到第
m-1
个节点:- 从头节点开始遍历链表,直到找到第
m-1
个节点。
- 从头节点开始遍历链表,直到找到第
-
反转从第
m
到第n
个节点:- 使用一个循环,将
curr
指向的节点插入到prev
和curr
之间,直到curr
指向第n
个节点。
- 使用一个循环,将
-
连接反转部分的前后节点:
- 将第
m-1
个节点的next
指向反转后的新头节点。 - 将反转部分的新尾节点的
next
指向第n+1
个节点。
代码实现
/** * struct ListNode { * int val; * struct ListNode *next; * }; */ /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param head ListNode类 * @param m int整型 * @param n int整型 * @return ListNode类 */ struct ListNode* reverseBetween(struct ListNode* head, int m, int n ) { // write code here if (head == NULL || m == n) { return head; } // 创建一个虚拟头节点,方便处理边界情况 struct ListNode dummy; dummy.next = head; struct ListNode* prev = &dummy; // 找到第 m-1 个节点 for (int i = 1; i < m; i++) { prev = prev->next; } // 当前节点指向第 m 个节点 struct ListNode* curr = prev->next; struct ListNode* next = NULL; // 反转从第 m 到第 n 个节点 for (int i = m; i < n; i++) { next = curr->next; curr->next = next->next; next->next = prev->next; prev->next = next; } return dummy.next; }
- 将第