链表中的节点每k个一组翻转
将给出的链表中的节点每k 个一组翻转,返回翻转后的链表
如果链表中的节点数不是k 的倍数,将最后剩下的节点保持原样
你不能更改节点中的值,只能更改节点本身。
要求空间复杂度 O(1)
示例
输入:{1,2,3,4,5},2
返回值:{2,1,4,3,5}
方法一 模拟法
将一条链表分块分为链表长度/k块链表,如果处不尽则说明后面会有剩下的那一块是不满长度为k的。在最初的时候需要定义两个NodeList表示result(结果)和 now(当前所到达的结果链表的位置)。之后遍历块的长度,对每一个链表块进行翻转,再翻转完后将完成的链表插入到now链表的下一个,再将now链表更新到最前即可。
public class Solution { /** * * @param head ListNode类 * @param k int整型 * @return ListNode类 */ public ListNode reverseKGroup (ListNode head, int k) { // write code here if(k <= 1) return head; if(head == null) return head; ListNode node = head; int len = length(head); head = node; int sx = len / k; //分成sx块向下取整(默认向下) 因为处不尽的后面必然凑不满k个 ListNode result = new ListNode(0); ListNode now = result; int cnt = 0; for(int i = 0; i < sx; i ++){ ListNode tmp = null; for(int j = 0; j < k; j ++){ //将第i块的元素翻转 ListNode bl = head.next; head.next = tmp; tmp = head; head = bl; } now.next = tmp; while(now.next != null) now = now.next; //将now更新到最前的一个点 } now.next = head; return result.next; } public int length(ListNode now){ //获取链表长度 int cnt = 0; if(now != null) cnt = 1; while(now.next != null){ cnt ++; now = now.next; } return cnt; } }
时间复杂度: O(n) 获取链表长度,翻转链表,和now变量的指位都需要遍历一次链表所以总时间复杂度为O(n).
空间复杂度: O(1) 只使用了若干个变量
方法二 栈
和方法一一样将链表分成每段长度为k的子链表,将每个链表存入栈中,当栈中有k个元素即可一一取出,之后按取出的顺序重组链表就是这一段中翻转的链表,要注意的是处理尾部不满长度为k的链表块时直接取栈底的元素做为最后一段即可。
public ListNode reverseKGroup (ListNode head, int k) { // write code here if(k <= 1 || head == null) return head; Deque<ListNode> st = new ArrayDeque<ListNode>(); //模拟栈 ListNode result = new ListNode(0); ListNode now = result; int cnt = 0; while(true){ for(int i = 0; i < k; i ++){ //将当前链表前k个存入栈中 st.push(head); head = head.next; cnt ++; if(head == null) break; } if(cnt == k){ //如果当前栈中有k个元素则一一取出存入链表 while(!st.isEmpty()){ now.next = st.pop(); now = now.next; now.next = null; } } if(head == null) break; //如果链表取完了跳出循环 cnt = 0; } ListNode end = null; while(!st.isEmpty()){ //如果栈中还有剩下的就说明是最后的一块直接取栈底即可 end = st.pop(); } now.next = end; return result.next; }
时间复杂度 O(n) 遍历了整个链表并且重组链表使用了时间为2n
空间复杂度 O(k) 栈中存入最大有k个ListNode