原题
Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
You may not alter the values in the nodes, only nodes itself may be changed.
Only constant memory is allowed.
For 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
题目大意
给定一个单链表,和一个分组数K,每K个结点进行反转,如果最后的结点数不足K个就保持原来的链接顺序不变。
解题思路
用一个指针记录链接好的链表的最后一个结点(tail),用一个指针记录上一次链接好的部分的最后一个结点(head)对未链表的结点在head处进行尾插法,插k个元素,再将head移动到tail处,tail重新记录链表的尾结点,直到所有的元素都进行了操作。如果最后的一组元素不足k个,因为进行过尾插法,所以还要进行还原,对最后的head元素进行尾插法就可以了
代码实现
结点类
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
算法实现类
public class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if (k <= 1) {
return head;
}
ListNode root = new ListNode(0);
// 分组的头一个元素的前驱
ListNode groupHead = root;
// 当前要处理的结点
ListNode curr = head;
// 处理好的链表的尾结点
ListNode groupTail = head;
// 当前要处理的结点的后继
ListNode next;
// 对每个组,处理了多少个结点
int count = 0;
while (curr != null) {
// 如果是分组的第一个元素就记录它
if (count == 0) {
groupTail = curr;
}
// 记录处理的元素个数
count++;
// 记录下一个待处理结点
next = curr.next;
// 进行尾插法操作
curr.next = groupHead.next;
groupHead.next = curr;
curr = next;
// 已经处理完了k个结点,分组头的前驱移动到最后一个链接好的结点
if (count == k) {
groupHead = groupTail;
// 计数器归零
count = 0;
}
}
// 说明结点个数不是k的整数倍,将最后不是整数倍的个元素的结点,
// 再次使用尾插法进行还原
if (count != 0) {
curr = groupHead.next;
groupHead.next = null;
while (curr != null) {
next = curr.next;
curr.next = groupHead.next;
groupHead.next = curr;
curr = next;
}
}
return root.next;
}
}
问题:
以k个元素为一组,反转单向链表。比如:
输入: 1->2->3->4->5->6->7->8->null and k = 3
输出:3->2->1->6->5->4->8->7->null.
分析:
我们可以把整个链表分成多个长度为 k 的子链表, 然后,我们再反转每一个子链表(递归)。问题的关键是我们需要把每个子链表再连接起来。所以,对每一个子链表操作以后,我们需要返回该子链表的头(head),然后,我们设置前一个子链表的最后一个node,把它的next 设置成下一个链表返回的头(head),这样,所有的子链表就连接起来了。
[java] view plain copy
- public static Node reverse (Node head, int k) {
- Node current = head;
- Node next = null;
- Node prev = null;
- int count = 0;
- /*reverse first k nodes of the linked list */
- while (current != null && count < k) {
- next = current.next;
- current.next = prev;
- prev = current;
- current = next;
- count++;
- }
- /* next is now a pointer to (k+1)th node
- Recursively call for the list starting from current.
- And make rest of the list as next of first node */
- if(next != null) {
- head.next = reverse(next, k);
- }
- /* prev is new head of the input list */
- return prev;
- }
这个问题也可以使用非递归的方法,基本上问题的处理方式和递归是一样的,但是,非递归的方式要稍微复杂一点,因为每次对子链表反转以后,我们需要更新前一个子链表最后一个node 的next 值。代码如下:
[java] view plain copy
- class Node {
- int val;
- Node next;
- Node(int x) {
- val = x;
- next = null;
- }
- }
- public class Solution {
- public static void main(String[] args) {
- Solution s = new Solution();
- Node n1 = new Node(1);
- Node n2 = new Node(2);
- Node n3 = new Node(3);
- Node n4 = new Node(4);
- Node n5 = new Node(5);
- n1.next = n2;
- n2.next = n3;
- n3.next = n4;
- n4.next = n5;
- Node head = s.ReverseInGroups(n1, 2);
- while (head != null) {
- System.out.println(head.val);
- head = head.next;
- }
- }
- public Node ReverseInGroups(Node current, int k) {
- if (current == null || current.next == null ) return current;
- //store the new head of the list
- Node newHead = null;
- //store the last node in the sub-list,
- //we will update its next value when finishing
- //reversing the next sub-list
- Node previousGroupTail = null;
- int count = 1; //used to track the first sub-list
- while (current != null) {
- // the actual tail in the sub-list
- Node groupTail = current;
- //reverse
- Node prev = null;
- Node next = null;
- for (int i = 1; i <= k && current != null; i++) {
- next = current.next;
- current.next = prev;
- prev = current;
- current = next;
- }
- // get the new head of the whole list
- if (count == 1) {
- newHead = prev;
- count++;
- }
- // update the next value of the last node in
- // each sub-list
- if (previousGroupTail != null) {
- previousGroupTail.next = prev;
- }
- previousGroupTail = groupTail;
- }
- return newHead;
- }
- }