递归反转链表,怎么就不会了呢
共 4820字,需浏览 10分钟
·
2021-02-20 20:45
Python实战社群
Java实战社群
长按识别下方二维码,按需求添加
扫码关注添加客服
进Python社群▲
扫码关注添加客服
进Java社群▲
LeetCode #206 反转链表 LeetCode #92 反转链表||
01
LeetCode #206 反转链表
public ListNode reverseList(ListNode head) {
// 调用递推公式反转当前结点之后的所有节点
// 返回的结果是反转后的链表的头结点
ListNode newHead = reverseList(head.next);
}
最后,将head指向的结点的下一个结点置为null,就完成了整个链表的反转。
将反转head指向的结点的代码完善之后,就可以得到如下的代码:
public ListNode reverseList(ListNode head) {
// 调用递推公式反转当前结点之后的所有节点
// 返回的结果是反转后的链表的头结点
ListNode newHead = reverseList(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
递归调用这一部分完成之后,还有重要的一步就是递归终止条件,递归反转链表什么时候停止呢?在head指向的结点为null或head指向的结点的下一个结点为null时停止,因为在这两种情况下,反转后的结果就是它自己。到这里,就可以写出完整的代码了:
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
// 调用递推公式反转当前结点之后的所有节点
// 返回的结果是反转后的链表的头结点
ListNode newHead = reverseList(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
02
LeetCode #92 反转链表||
1 ≤ m ≤ n ≤ 链表长度。
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
为了方便说明一个问题,这里以链表1->2->3->4->5->6->NULL, m = 3, n = 5为例进行分析如何用递归思想求解该题目。
public ListNode reverseBetween(ListNode head, int m, int n) {
ListNode between = reverseBetween(head.next, m-1,n-1);
}
public ListNode reverseBetween(ListNode head, int m, int n) {
ListNode between = reverseBetween(head.next, m-1,n-1);
head.next = between;
return head;
}
递推公式的部分已经完成了,接着要明确的就是递归终止条件。在这里原问题是反转链表:1->2->3->4->5->6->NULL, m = 3, n = 5之间的部分。
更小的子问题是反转链表:2->3->4->5->6->NULL, m = 2, n = 4之间的部分。
在进一步是反转链表:3->4->5->6->NULL, m = 1, n = 3之间的部分。但是,这时这个子问题和上一个子问题还是可以用相同思路求解的同一个子问题吗?
public ListNode reverseBetween(ListNode head, int m, int n) {
if (m == 1) {
return 待补充;
}
ListNode between = reverseBetween(head.next, m-1,n-1);
head.next = between;
return head;
}
这里,递推公式reverseTopN的含义是反转链表的前n个结点并返回被反转的链表的头结点。因此,其需要的参数有两个,一是待反转的链表的头结点,二是反转前几个结点,即n。
至此,对于反转链表的前n个结点,可以初步写出如下的代码:
private ListNode reverseTopN(ListNode head, int n) {
ListNode newHead = reverseTopN(head.next, n-1);
}
经过前面分析,我们知道head指向的结点3也是需要反转的,即head.next.next=head。但是,我们发现在完成这一步操作后,结点6没法在和其它结点产生联系了。
这时,在反转结点3,即head.next.next=head之后,我们可以将topNSuccessor指向的结点挂在head指向的结点之后,即head.next=topNSuccessor。
这时,反转链表前N个结点的代码进一步完善如下:
private ListNode reverseTopN(ListNode head, int n) {
ListNode newHead = reverseTopN(head.next, n-1);
head.next.next = head;
head.next = topNSuccessor;
return newHead;
}
ListNode topNSuccessor = null;
private ListNode reverseTopN(ListNode head, int n) {
if (n == 1) {
topNSuccessor = head.next;
return head;
}
ListNode newHead = reverseTopN(head.next, n-1);
head.next.next = head;
head.next = topNSuccessor;
return newHead;
}
public ListNode reverseBetween(ListNode head, int m, int n) {
if (m == 1) {
return reverseTopN(head, n);
}
ListNode between = reverseBetween(head.next, m-1,n-1);
head.next = between;
return head;
}
ListNode topNSuccessor = null;
private ListNode reverseTopN(ListNode head, int n) {
if (n == 1) {
topNSuccessor = head.next;
return head;
}
ListNode newHead = reverseTopN(head.next, n-1);
head.next.next = head;
head.next = topNSuccessor;
return newHead;
}
题图:rahu / Pixabay
近期精彩内容推荐: