描述
将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)。
例如:给出的链表为 1->2->3->4->5->NULL,m=2,n=4
返回 1->4->3->2->5->NULL
思路1:两次遍历
- 遍历找到要反转链表的前一个节点pre,即1
- 子链表的头节点left=pre.next,即2
- 遍历找到子链表的后一个节点5
- 反转链表4->3->2->5,并返回新的头节点
- 将pre连接上子链表
不足:当m和n相距过大时,反转子链表成本较大
public class Solution {
public ListNode reverseBetween (ListNode head, int m, int n) {
ListNode node = new ListNode(-1);
node.next = head;
ListNode pre = node;
//length为子链表长度
int length = n - m;
//找到反转链表的前一个节点
while(m > 1) {
m--;
pre = pre.next;
}
//从子链表开始遍历,找到子链表的后一个节点
ListNode left = pre.next;
ListNode tail = left;
while(length >= 0) {
length--;
tail = tail.next;
}
pre.next = reverse(left, tail);
return node.next;
}
ListNode reverse(ListNode head, ListNode tail) {
ListNode cur = tail;
while(head != tail) {
ListNode tmp = head.next;
head.next = cur;
cur = head;
head = tmp;
}
return cur;
}
}
思路2:一次遍历
- 遍历找到要反转链表的前一个节点pre,即1
- 子链表的头节点left=pre.next,即2
- 反转长度为length的子链表:4->3->2
- 将2指向子链表的后一个节点:4->3->2->5
- 将pre接上子链表
和思路1不同的是,子链表的后一个节点需要遍历反转之后才能得到
public class Solution {
public ListNode reverseBetween (ListNode head, int m, int n) {
ListNode node = new ListNode(-1);
node.next = head;
ListNode pre = node;
int length = n - m;
//找到子链表的前一个节点
while(m > 1) {
m--;
pre = pre.next;
}
//反转长度为length的子链表,并返回反转链表的头节点
ListNode left = pre.next;
pre.next = reverse(left, length);
return node.next;
}
ListNode reverse(ListNode head, int length) {
//保存子链表的头节点
ListNode left = head;
ListNode cur = null;
while(length >= 0) {
ListNode tmp = head.next;
head.next = cur;
cur = head;
head = tmp;
length--;
}
//指向子链表的后一个节点
left.next = head;
return cur;
}
}
思路3:使用栈
- 遍历找到要反转链表的前一个节点pre,即1
- 遍历将子链表节点全部入栈
- 保存子链表的后一个节点
- 将栈中元素出栈,接在原链表后面
- 连接上子链表的后一个节点
public class Solution {
public ListNode reverseBetween (ListNode head, int m, int n) {
ListNode node = new ListNode(-1);
node.next = head;
ListNode pre = node;
Stack<ListNode> stack = new Stack<>();
int length = n - m;
while(m > 1) {
m--;
pre = pre.next;
}
head = pre.next;
for(int i = 0; i <= length; i++) {
stack.push(head);
head = head.next;
}
while(!stack.isEmpty()) {
pre.next = stack.pop();
pre = pre.next;
}
pre.next = head;
return node.next;
}
}