Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
Example:
Given this linked list: 1->2->3->4->5 For k = 2, you should return: 2->1->4->3->5 For k = 3, you should return: 3->2->1->4->5
Note:
- Only constant extra memory is allowed.
- You may not alter the values in the list's nodes, only nodes itself may be changed.
本题是LeetCode 24. Swap Nodes in Pairs —— 两两交换链表中的节点的升级版。同时结合LeetCode 206. Reverse Linked List —— 反转链表就会有很多想法。
本题相当于将原链表的每个长度为k的子链表进行反转,之后再将逐段反转后的结果拼接起来。需要注意的是如果最后一段子链表不足k个,那就不需要反转。所以思路就很清晰了,先求出整个链表的长度,之后分割成k段,每段调用206题的程序反转子链表,之后将结果拼接即可。其实这样做每次都遍历了两次原链表,一次是分段,一次是反转分段后的链表(再加上计算长度,总共三次)。但运算速度竟然很高!再一次验证了LeetCode上的case可能都比较短吧…
当然此题还可以用递归来做,依然是利用缩小规模后的结果去计算更大规模的问题。详见代码注释。
解法一(Java)
class Solution { public ListNode reverseKGroup(ListNode head, int k) { //计算链表长度 int count = 0; ListNode cur = head; while (cur != null) { count++; cur = cur.next; } ListNode preHead = new ListNode(0); //建立假节点存出结果 preHead.next = head; ListNode pre = preHead; while (count >= k) { ListNode end = head; for (int i = 1; i < k; i++) //计算出每k段子链表的尾节点 end = end.next; ListNode nextHead = end.next; //存储下一段子链表的开始 end.next = null; //分割链表 pre.next = reverseList(head); //反转子链表 head.next = nextHead; //把反转后的子链表的尾节点与下一段链表头拼接 pre = head; //移动指针到下一段链表头的前驱 head = pre.next; //对下一个子链表进行相同操作 count -= k; } return preHead.next; } //见206题 public ListNode reverseList(ListNode head) { ListNode first = head; ListNode reverseHead = null; while (first != null) { ListNode second = first.next; first.next = reverseHead; reverseHead = first; first = second; } return reverseHead; } }
解法二(Java)
class Solution { public ListNode reverseKGroup(ListNode head, int k) { ListNode cur = head; int count = 0; while (count < k && cur != null) { cur = cur.next; count++; } //分段递归 if (count == k) { cur = reverseKGroup(cur, k); //cur存储反转k各节点之后的链表 while (count > 0) { //反转本段链表,相当于以head为指针再一次遍历前k个节点,把从head开始的每一个节点放到cur前,然后head向后移动,cur向前移动,直到k次 ListNode nextHead = head.next; head.next = cur; cur = head; head = nextHead; count--; } head = cur; //把head重新放回到表头用以返回结果 } return head; } }