92. 反转链表 II
给你单链表的头节点 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
反转链表
非递归解法
-
反转cur.next
cur.next = pre ; pre = cur; cur = next next = cur.next;
-
新建一个头结点,头插法(哨兵法)
head.next = cur;
cur = cur.next;
return head.next;
递归解法
思路:将两个结点间的指针换个方向
递归到底部:
递归回根:
void reverse(ListNode head)
{
if(head.next = null) return head;
ListNode last = reverse(head);
head.next.next = head;
head.next=null;
}
本题解法
1.基于非递归
- 由于翻转指定区间,反转区间外的两个指针无论是否空都不处理,所以要做好判断。
public ListNode reverseBetween(ListNode head, int left, int right) {
if(left==right||left>right) return head;
int now = 1;
ListNode ppre = null,p=head;
while(now!=left){
//确定反转区间和反转指针前的第一个指针
ppre = p;
p = p.next;
now++;
}
ListNode pre = p, cur = p.next, next = cur.next, tail = p;
while(cur!=null){
cur.next = pre;
pre = cur;
cur = next;
if(now>=right-1){
//最后一步,处理反转区间外的连接
tail.next = next; //反转区间的头指针被处理到区间的末尾了
if(ppre!=null)ppre.next = pre;
break;
}
next = cur.next;
now++;
}
return ppre==null?pre:head; //left为1 ppre为空,head被处理了
}
2.基于递归
ListNode successor = null; // 后驱节点
// 反转以 head 为起点的 n 个节点,返回新的头结点
ListNode reverseN(ListNode head, int n) {
if (n == 1) {
// 记录第 n + 1 个节点
successor = head.next;
return head;
}
// 以 head.next 为起点,需要反转前 n - 1 个节点
ListNode last = reverseN(head.next, n - 1);
head.next.next = head;
// 让反转之后的 head 节点和后面的节点连起来
head.next = successor;
return last;
}
public ListNode reverseBetween(ListNode head, int m, int n) {
// base case
if (m == 1) {
return reverseN(head, n);
}
// 前进到反转的起点触发 base case
head.next = reverseBetween(head.next, m - 1, n - 1);
return head;
}