25.K个一组翻转链表
集合
思路
-
存入集合
-
在集合中进行翻转
-
遍历操作后的集合 ,构建新的链表
-
很明显 过程耗时间空间
代码
/**
*6ms 7%
*/
public ListNode reverseKGroup(ListNode head, int k) {
if(head==null) return null;
//存入集合
List<ListNode> nodes=new ArrayList<>();
while(true){
if(head==null){
break;
}
nodes.add(head);
head=head.next;
}
// System.out.println(nodes.toString());
int len=nodes.size();
int mode=len%k;
for(int i=0;i<len-mode;i+=k){
//首尾交换规律
int index=i+(i+k-1);
for(int j=i;j<i+k/2;j++){
ListNode temp=nodes.get(j);
nodes.set(j,nodes.get(index-j));
nodes.set(index-j,temp);
}
}
ListNode head2=new ListNode(-1);
ListNode temp=head2;
nodes.get(len-1).next=null;//若设置末尾为null 例如[1,2] 翻转后[2,1] 但此时1.next.val=2,构成死循环
for(ListNode node:nodes){
temp.next=node;
temp=temp.next;
}
// list(head2.next);
return head2.next;
}
栈
-
使用 栈 进行链表交换
代码
/** * 使用栈进行交换 * 3ms 12% */ public ListNode reverseKGroup2(ListNode head, int k) { Stack<ListNode> stack=new Stack<>(); ListNode dummy=new ListNode(-1); ListNode p=dummy; while(true){ int count=0; ListNode tmp=head; while(tmp!=null&&count<k){ stack.add(tmp); tmp=tmp.next; count++; } if(count!=k){ p.next=head; break; } while(!stack.isEmpty()){ p.next=stack.pop(); p=p.next; } p.next=tmp; head=tmp; } return dummy.next; }
头插法
参考原文王小二:图解k个一组翻转链表
图解如下:
代码
/**
* 0ms
*/
public ListNode reverseKGroup3(ListNode head,int k){
ListNode dummy=new ListNode(-1);
dummy.next=head;
ListNode pre=dummy;
ListNode end=dummy;
while(end.next!=null){
for(int i=0;i<k&&end!=null;i++) end=end.next;
if(end==null) break;
ListNode start=pre.next;
ListNode next=end.next;
end.next=null;
pre.next=reverse(start);
start.next=next;
pre=start;
end=pre;
}
return dummy.next;
}
public ListNode reverse(ListNode head){
ListNode pre=null;
ListNode cur=head;
while(cur!=null){
ListNode next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
问题
链表操作(交换)与数组操作 有很大区别 ,数组交换主要是值的交换,而链表是整体。同时需妥善处理next指针,稍不注意易造成节点死循环。 例如[1,2] 翻转后[2,1] 若1.next不设置成null,此时1.next.val=2,构成死循环。