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个节点进栈,然后按照出栈的顺序连接起来,则自然反转,最后不足k个节点,就直接返回首节点。
代码方面也参照了上一题的迭代方法,很简洁。
public ListNode reverseKGroup(ListNode head, int k) {
Stack<ListNode> st = new Stack<ListNode>();
ListNode temp = head;
for(int i = 0; i < k ; i++){
if(head != null){
st.push(head);
}else{
return temp;
}
head = head.next;
}
ListNode first = st.pop();
ListNode res = first;
for(int i = 0; i<k-1; i++){
first.next = st.pop();
first = first.next;
}
first.next = reverseKGroup(head,k);
return res;
}
但是呢,用stack一方面速度较慢,另一方面万一内存溢出就不好玩了,所以我下面采用了另一种方法来反转。其实链表的反转是一个经典题目,这个过程之前也看到过,这里只是有一点点的不一样,即不是反转全部链表,而是一部分一部分的反转。就单部分反转来说,思路是一样的。
思路如下:每次都将原第一个结点之后的那个结点放在头节点的后面,下图是原始的单链表。
为了反转这个单链表,我们先让头结点的next域指向结点2,再让结点1的next域指向结点3,最后将结点2的next域指向结点1,就完成了第一次交换,顺序就变成了Header-结点2-结点1-结点3-结点4-NULL,然后进行相同的交换将结点3移动到结点2的前面,然后再将结点4移动到结点3的前面就完成了反转。
写代码的时候呢,用root.next指向子链表里的第一个节点,head为第一个节点,反转一次即变成第二个几点,从而保证他后面的节点就是下一个将被放到前面的节点。用一个临时节点保存root后面的节点,被交换到前面的节点将指向这个临时节点。代码如下~运行时间缩短到1ms
public ListNode reverseKGroup(ListNode head, int k) {
ListNode root = new ListNode(-1);
root.next = head;
ListNode res = root;
ListNode temp = head;
int i = 0;
while(temp != null){
i++;
temp = temp.next;
}
while(i >= k){
for(int j = 0 ; j < k-1; j++){
ListNode node = root.next;
root.next = head.next;
head.next = root.next.next;
root.next.next = node;
}
root = head;
head = head.next;
i-=k;
}
return res.next;
}