1.思路分析
反转链表的前k个结点其实与反转链表差别不大,关键点在于我们如何提前结束反转链表,在反转链表中,我们的结束条件是什么呢?head.next == null,欧克,现在我们只要修改这个条件就能达到提前结束反转链表,只反转链表的前n个结点。
2.具体分析
a.传入第k+1个结点
在反转链表中,我们这里的k就是整个链表的长度,也就是说,其实反转链表是反转链表前n个结点的特殊情况罢了。那现在我们就要从特殊分析一般的情况,
| 反转结点数 | 结束条件 | |
|---|---|---|
| 反转链表 | n(链表的长度) | head.next == null |
| 反转链表前k个结点 | k(k<=n) | ? |
?代表的是什么条件,让我们来想想看,n个时,head.next指向null为终止,null所在的位置不就是第n个结点的后一个吗?那一切就明白了,通用的结束条件应该是head.next == ‘第k+1个结点’,有了这个我们就能写出代码了。
public ListNode reverseK(ListNode head, ListNode kplusOne) {// head.next == null才是base case ,head == null是为简洁而合并的if(head == null||head.next == kplusOne) return head;//递归公式ListNode last = reverseList(head.next);head.next.next = head;head.next = null;//转换headreturn last;}
哎?这样写真的正确吗?

通过上面这过程,我们突然发现了问题,head.next = null后,第k个结点后面的部分不就都丢失了吗?要怎么更改代码呢?让我们想想反转整个链表的时候,为什么要指向null,你可能会说,因为后面没有节点了啊,肯定指向null,不然还能指向啥?那再想想,如果后面有结点呢?那肯定指向后面的结点,对吧,这下我们就分析清楚啦!此时后面有结点我们不能指向null,要指向后面不反转的结点。
public ListNode reverseK(ListNode head, ListNode kplusOne) {// head.next == null才是base case ,head == null是为简洁而合并的if(head == null||head.next == kplusOne) return head;//递归公式ListNode last = reverseList(head.next);//保留不反转的部分ListNode rest = head.next.next;head.next.next = head;//指向不反转的部分head.next = rest;//转换headreturn last;}
欧克,这下就正确了,但是还没有完,你要问了,题目只给了你k这个参数,该怎么办呢?
b.传入K
这并不难,我前面说过,只要找到结束条件就可以了。

我们使用递归就是因为可以把原问题分解为相同的子问题,原问题可以由子问题一层一层往上解决,而最终解决。我们是求前K个结点,当往下的时候,就是求下一个链表的前K-1个结点,直到K==1的时候,我们结束了,因为反转前1个结点就等于没有反转,这其实也是递归反转链表的核心思想。
public ListNode reverseK(ListNode head, int k) {if(k == 1) return head;//递归公式ListNode last = reverseList(head.next, k-1);//保留不反转的部分ListNode rest = head.next.next;head.next.next = head;//指向不反转的部分head.next = rest;//转换headreturn last;}
