如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
思路分析:
在宏观视角看递归这篇文章中,我们说链表具有天然的递归属性,因为一个链表,可以看做是一个节点后挂着另一个链表,即递归中更小的子问题。
那么对于题目给定的链表其更小的子问题是什么呢?
由于是k个一组反转链表,所以对于给定的链表除去前k个节点,剩余的节点组成的链表依旧满足k个一组反转链表这个条件,这就是这个题目的子问题。
子问题有了,就可以初步写出如下的递归代码,其中subList是除去前k个节点后剩余的链表k个一组反转后的头结点。
public ListNode reverseKGroup(ListNode head, int k) {// 递归反转链表中除去前k个节点的后续节点ListNode subList = reverseKGroup(除去前k个节点后剩余的链表,k);}接着,我们看下如何确定除去前k个节点后剩余的链表这个问题。
方法是从头节点head开始遍历链表,遍历的过程中记录已遍历的节点个数remainNum,同时用变量nextHead记录下一个待遍历的节点。 当remainNum与k相等时,变量nextHead指向的节点及其之后的所有节点就是除去前K个节点之后剩余的链表。至此,代码可以进一步完善如下:
public ListNode reverseKGroup(ListNode head, int k) {// nextHead指向链表中除去k个节点之后的头节点// 初始指向节点headListNode nextHead = head;// 链表中剩余节点个数int remainNum = 0;while (remainNum < k){remainNum++;nextHead = nextHead.next;}// 递归反转链表中除去前k个节点的后续节点ListNode subList = reverseKGroup(nextHead,k);}细心的你应该注意到,在这里有一个问题,那就是如果剩余的节点个数小于K,那么上述代码中的while循环内nextHead=nextHead.next就会出现空指针的问题。
剩余的节点个数小于K的情况,根据题意可知,这时不需要对这些节点进行反转,因此对于这种情况直接返回即可。这也是这道题目的递归终止条件。 到这里,代码可以进一步完善如下:
public ListNode reverseKGroup(ListNode head, int k) {// nextHead指向链表中除去k个节点之后的头节点// 初始指向节点headListNode nextHead = head;// 链表中剩余节点个数int remainNum = 0;while (remainNum < k){// 根据题意如果链表剩余节点个数不足k个// 则不需要反转,因此直接返回headif (nextHead == null) {return head;}remainNum++;nextHead = nextHead.next;}// 递归反转链表中除去前k个节点的后续节点ListNode subList = reverseKGroup(nextHead,k);}接着我们看下对于题目给出的示例,经过上述代码逻辑处理后是一个什么结果。
在这里我们以k=2为一组进行链表反转。因此,在除去前2个节点后,nextHead指向节点3。在经过reverseKGroup(nextHead,2)递归反转后,链表结构如下图所示。注意在这里,不要试图去在大脑中复现reverseKGroup这个递推公式的调用过程,只需知道其执行后的结果就可以了。
到此,我们完成了除去前2个节点之后,剩余节点的反转。接着要做的是反转前k=2个节点。反转后结果如下图所示:
这时,只需将head的后继指针指向变量subList所指向的节点,就完成了K个一组反转链表这个任务。 在加上反转链表中前k个节点的代码后,代码进一步完善如下:
public ListNode reverseKGroup(ListNode head, int k) {// nextHead指向链表中除去k个节点之后的头节点// 初始指向节点headListNode nextHead = head;// 链表中剩余节点个数int remainNum = 0;while (remainNum < k){// 根据题意如果链表剩余节点个数不足k个// 则不需要反转,因此直接返回headif (nextHead == null) {return head;}remainNum++;nextHead = nextHead.next;}// 递归反转链表中除去前k个节点的后续节点ListNode subList = reverseKGroup(nextHead,k);// 反转链表中前k个节点ListNode newHead = reverseTopN(head, k);// 前k个节点反转后,head指向的节点是反转后的链表中的最后一个节点// 因此head指向的节点的后继指针指向subListhead.next = subList;return newHead;}最后我们看下如何反转链表中的前K个节点。动画演示如下: 反转前K=2个节点
反转前K个节点的代码实现如下:
private ListNode reverseTopN(ListNode head, int n) {ListNode prev = null;// 当前考察的节点ListNode cur = head;// num小于n,则表示当前节点需要反转for(int num = 0; num < n; num++){// 当前节点的下一个节点ListNode next = cur.next;// 当前节点的后继指针指向prevcur.next = prev;// prev指向当前节点// 表示其是next节点反转后的前一个节点prev = cur;// cur指向下一个节点// 表示下一个节点是待反转节点cur = next;}return prev;}今天的分享就到这里了
如有错误 欢迎在公众号后台留言指出 下一篇我们将学习新的内容,敬请期待








