题目
给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序。
示例 :
给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明 :
- 你的算法只能使用常数的额外空间。
- 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
题解
无官方题解
执行用时 : 2 ms, 在Reverse Nodes in k-Group的Java提交中击败了86.58% 的用户
内存消耗 : 38 MB, 在Reverse Nodes in k-Group的Java提交中击败了82.96%的用户
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if(head==null||head.next==null||k==1) return head;
ListNode dummy = new ListNode(-1);
dummy.next=head;
ListNode pos;//存下一个位置
ListNode tmp=dummy;//用来存前一个K组的最后一个
ListNode test=head;//下一个K组的第一个
int i=0;
for(i=0;i<k;i++){//初始化test的位置
if(test.next!=null){
test=test.next;
}
else{
test=null;
break;
}
}
while (test!=null){
pos=head.next;//记录一下下一个的位置
head.next=test;//第一个连向下一个K组的第一个
head=pos;
pos=pos.next;
while(head!=test){
head.next=tmp.next;
tmp.next=head;
head=pos;
pos=pos.next;
}
for(i=0;i<k;i++){
if(test.next!=null){
test=test.next;
tmp=tmp.next;
}
else{
test=null;
break;
}
}
}
if(i==k-1){
if(tmp!=dummy)tmp=tmp.next;//这个tmp不往后走一个的话75/81[1,2,3,4]用例过不去,因为tmp位置不对。不加判定也不行,66/81[1,2]过不去
pos=head.next;//记录一下下一个的位置
head.next=null;//第一个连向下一个K组的第一个
head=pos;
pos=pos.next;
while(head!=null){
head.next=tmp.next;
tmp.next=head;
head=pos;
if(pos!=null)pos=pos.next;
}
}
return dummy.next;
}
}
看到评论区一个答案,看上去比较6,贴过来供参考一下:
执行用时 : 1 ms, 在Reverse Nodes in k-Group的Java提交中击败了99.79% 的用户
内存消耗 : 35 MB, 在Reverse Nodes in k-Group的Java提交中击败了100.00% 的用户
两个递归,分治。一个递归负责翻转,一个递归负责遍历拼接
public ListNode reverseKGroup(ListNode head, int k) {
if (head == null) {
return null;
}
if (k == 1){
return head;
}
int count = 0;
ListNode pre = head;
ListNode temp = head;
for (; count < k; count++) {//向后检查k位
if (temp != null) {//temp在后面为pre开路
pre = temp;
temp = temp.next;
}else {
break;
}
}
if (count<=k-1){//如果前面中间碰到temp==null,break了,执行这个
return head;
}
pre.next = null;//pre.next设为null用来判断下面rev的终止递归点
ListNode rev = rev(null, head);
head.next = reverseKGroup(temp, k);//递归连接后面的结果
return rev;
}
public static ListNode rev(ListNode pre, ListNode cur) {//用来翻转前面确定可以翻转的部分
if (cur == null) {
return pre;
}
ListNode next = cur.next;
cur.next = pre;
return rev(cur, next);
}
感想
自己实现的速度倒是可以,就是代码写的比较丑,test的判断有点恶心了。
分治法还是应该很有参考价值的。自己就是因为没用分治,导致在开始、结束时需要引入额外的判断方式。代码就不够简洁了。