题目介绍
力扣92题:leetcode-cn.com/problems/re…
方法一
该题是[反转链表]的变形,思路都是差不多的,我们首先需要定位到left
对应节点的上一个节点preLeft
,以及right
对应的节点的下一个节点nextRight
,为什么要定位到这两个节点呢?为了后面反转之后的节点拼接。总体步骤如下:
- 首先找到
preLeft
和nextRight
- 将需要反转的部分进行反转
- 反转之后进行节点拼接
代码如下:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
if(head == null || head.next == null || right == 1 || left == right) {
return head;
}
ListNode dumy = new ListNode(-1);//哑节点
dumy.next = head;
ListNode p = dumy;
ListNode preLeft = null;//反转部分的左边前一个指针
ListNode leftNode = null;//left对应的节点
ListNode rightNode = null;//right对应的节点
ListNode prev = null;
ListNode nextRight = null;//反转部分的右边下一个指针
for(int i = 0 ; p != null ; i++) {
if(i == left - 1) {
preLeft = p;
leftNode = p.next;
}
if((i == right) && (p.next != null)) {
nextRight = p.next;
}
if (i == right) {
rightNode = p;
}
p = p.next;
}
//开始反转从left到right的节点
p = leftNode;
while(p != nextRight) {
//事先保存cur的下一个节点
ListNode next = p.next;
p.next = prev;
prev = p;
p = next;
}
//将反转之后的节点进行拼接
preLeft.next = rightNode;
leftNode.next = nextRight;
return dumy.next;
}
}
复杂度分析
- 时间复杂度:O(n)。
- 空间复杂度:O(1)。
方法二:双指针-头插法
1、我们定义两个指针,分别称之为 g(guard 守卫) 和 p(point)。
我们首先根据方法的参数 m 确定 g 和 p 的位置。将 g 移动到第一个要反转的节点的前面,将 p 移动到第一个要反转的节点的位置上。我们以 m=2,n=4为例。
2、将 p 后面的元素删除,然后添加到 g 的后面。也即头插法。
3、根据 m 和 n 重复步骤(2)
4、返回 dummyHead.next
代码如下:
class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
// 定义一个dummyHead, 方便处理
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
// 初始化指针
ListNode g = dummyHead;
ListNode p = dummyHead.next;
// 将指针移到相应的位置
for(int step = 0; step < m - 1; step++) {
g = g.next; p = p.next;
}
// 头插法插入节点
for (int i = 0; i < n - m; i++) {
ListNode removed = p.next;
p.next = p.next.next;
removed.next = g.next;
g.next = removed;
}
return dummyHead.next;
}
}