leetcode链表反转(递归)总结——全部翻转,部分反转
- 由于链表反转使用迭代的思路进行实现比较简单,只是写法上比较复杂,所以这里仅整理记录一下递归反转链表的解法
一.全部反转
1.1 题目
- 使用递归反转链表,并返回链表
1.2 解法
/**
* 递归反转链表
* @param head
* @return
*/
public static ListNode reverseList(ListNode head) {
if(head.next == null){
return head;
}
ListNode last = reverseList(head.next);
head.next.next = head;
head.next = null;
return last ;
}
1.3 算法过程详解
- 对于递归切记的就是看代码的时候不要进去,因为脑子里根本没法压多个栈,一旦进入递归了,那么就把整个思路复杂化了。
- 我们只需要关注两个地方:
1) 第一个就是整个方法的作用是什么(传入值,操作,返回值)。
2) 第二个就是base case,当递归到最底层了,该怎么操作,返回什么 - 在链表递归反转的操作中,往往最重要的是反向操作,也就是递归到最后一个节点或者倒数第二个节点了,该怎么反转链表
1)递归操作(这里就是进行递归的地方)
ListNode last = reverseList(head.next);
函数的传入值:后置链表(head后面的链表)
函数的作用:将后置链表进行反转
函数的返回值:返回反转之后的第一个节点(也就是反转之前的最后一个节点)
注意:在这里我们无需关注函数是如何反转的,我们只需要关注返回的是什么,里面已经干了什么
假设我们想反转这个链表:
那么执行完这一步之后,已经变成了这个样子:
- 此时head指向1,last 指向6,后置链表已经全部反转
- 之后我们就要开始将1也开始加入反转链表中
2)反转操作
- 第一行代码是让2的next指向1
- 第二行的代码是让1的next指向null
- 此时就已经完成了整个链表的反转
head.next.next = head;
head.next = null;
完成上述操作后,该链表已经变成这样:已经完成了整个链表的反转
3)base case
- 当递归到最后一个节点的时候,返回该节点即可
if(head.next == null){
return head;
}
至此,已经完成了链表反转操作,实际上这个函数会一直递归到倒数第二个节点,中间的反转操作会在倒数第二个节点开始进行操作,直到递归到第一个节点,中间的每一个节点都会进行反向操作,这也就是我之前说的为什么反向操作是最核心的地方。
二. 反转前n个节点
2.1 解法
/**
* 递归反转前n个节点
* @return
*/
ListNode successor;
public ListNode reverseListN(ListNode head, int n) {
if(n == 1){
successor= head.next;
return head;
}
ListNode last = reverseListN(head.next,n-1);
head.next.next = head;
head.next = successor;
return last;
}
2.2 算法过程详解
- 实际上反转前n个链表节点跟反转全部节点区别仅仅在于base case和最后连接整个链表的操作。
- 这个n的意义仅仅是判断是否到达了最后一个要反转的链表节点,也就是base case的判断条件点
reverseListN(head.next,n)
- 整个大方法的作用就是将前n个链表节点反转,并返回第n个节点指针
1)递归
ListNode last = reverseListN(head.next,n-1);
- 方法返回last指向的就是第n个节点
2)操作
- 反转操作,将该节点也加入反转
head.next.next = head;
3)base case
if(n == 1){
successor= head.next;
return head;
}
- 这里的successor指向的是第n+1个节点,因为将前n个节点反转之后,还需要将后面的节点连起来,所以需要记录
4)连接链表
head.next = successor;
三. 反转部分链表
3.1 题目
3.2 思路
- 如果上面的链表看懂了,其实反转部分链表就非常简单了,因为只需要定位到需要反转链表的第一个节点,再使用反转前n- m个节点的方法就可以完成操作
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;
}