K个一组反转链表

学到的写法

 public ListNode reverseKGroup_v2(ListNode head, int k){
        ListNode pHead = new ListNode(-1, head);
        ListNode pre = pHead;
        while(true){
            ListNode last =  pre.next;
            for(int i=0;i<k;i++){
                if (last== null){
                    return pHead.next;
                }
                last = last.next;
            }
            ListNode cur = pre.next;
            for (int j=0;j<k-1;j++){
                ListNode next = cur.next;
                cur.next = next.next;
                next.next = pre.next;
                pre.next = next;
            }
            pre = cur;
        }
    }

自己一遍过的愚蠢代码,虽蠢但过

private  Map<ListNode, Integer> listNodeMap  = new HashMap<>();
    private  Map<Integer,ListNode>listNodeMapR = new HashMap<>();
    /**
     * 存放每k段头尾的映射,为了再次连接
     */
    private  Map<ListNode, ListNode> listNodeMapTail = new HashMap<>();
    private  List<ListNode> subListNodes = new ArrayList<>();
    public  ListNode reverseKGroup(ListNode head, int k) {
        ListNode pHead = head;
        int count = 0;
        while(pHead != null){
            count++;
            listNodeMap.put(pHead, count);
            listNodeMapR.put(count,pHead);
            pHead =  pHead.next;
        }

        ListNode result = new ListNode(-1);
        ListNode temp = result;
        cutKListNode(head,k);
        for (ListNode node:subListNodes){
            int addKIndex = listNodeMap.get(node)+k-1;
            if (addKIndex<=count){
                ListNode subListNode = reverseListNode(node, k);
                temp.next = subListNode;
                temp = listNodeMapTail.get(subListNode);
            }else {
                temp.next = node;
            }
        }
        return result.next;
    }


    /**
     * 反转链表
     * @param listNode
     * @param k
     * @return
     */
    private  ListNode reverseListNode(ListNode listNode,Integer k){
        ListNode newNode = new ListNode(-1);
        int currentIndex = listNodeMap.get(listNode);
        ListNode subTail = listNode;
        while(listNode != null && listNodeMap.get(listNode)-currentIndex<k){
            listNodeMapTail.put(listNode, subTail);
            ListNode nextNode = listNode.next;
            listNode.next = newNode.next;
            newNode.next = listNode;
            listNode = nextNode;
        }
        return newNode.next;
    }

    /**
     * 切链表为每k一段
     * @param head
     * @param k
     */
    private void cutKListNode(ListNode head, int k){
        while(head != null){
            subListNodes.add(head);
            int index = listNodeMap.get(head);
            head = listNodeMapR.get(index+k);
        }
    }
### 实现方法 在链表操作中实现每 `k` 个节点为一组进行反转,通常采用递归和迭代相结合的方法。该方法的核心思想是分组处理链表中的节点,每组包含 `k` 个节点,并对每组内的节点进行反转,最后将反转后的子链表重新连接起来。 #### 1. 反转指定区间的链表 首先,需要实现一个辅助函数来反转链表中从 `start` 到 `end` 的子链表。该函数的核心逻辑是将指定区间内的节点逐个反转[^1]。例如,可以使用迭代的方式反转链表: ```python def reverse(start, end): prev = None curr = start while curr != end: next_node = curr.next curr.next = prev prev = curr curr = next_node return prev ``` #### 2. 分组处理链表 接下来,通过递归的方式遍历整个链表并分组处理。每次从链表的当前头部开始,找到一组 `k` 个节点,如果不足 `k` 个节点,则直接返回链表的头部,无需反转。否则,对这 `k` 个节点进行反转,并递归处理后续的链表部分[^3]。 ```python def reverseKGroup(head, k): if head is None: return head a = b = head # 找到第k个节点 for _ in range(k): if b is None: return head b = b.next # 反转前k个节点 new_head = reverse(a, b) # 递归处理后续的链表,并连接当前组的末尾 a.next = reverseKGroup(b, k) return new_head ``` #### 3. 处理细节 在具体实现时,需要注意以下几点: - **边界条件**:当链表长度不足 `k` 时,直接返回原始链表。 - **断开连接**:在反转链表之前,需要将该子链表从原链表中暂时断开,避免反转时影响其他部分。 - **重新连接**:反转完成后,将反转后的子链表重新连接到原链表中,并处理前后指针的指向。 #### 4. 时间复杂度与空间复杂度 - **时间复杂度**:由于每个节点最多会被访问两次(一次用于遍历,一次用于反转),因此总的时间复杂度为 `O(n)`,其中 `n` 是链表的长度。 - **空间复杂度**:递归调用栈的深度最多为 `n/k`,因此空间复杂度为 `O(n/k)`。 #### 5. 示例图解 以链表 `1 -> 2 -> 3 -> 4 -> 5` 和 `k=2` 为例: - 第一组反转 `1 -> 2`,得到 `2 -> 1`。 - 第二组:反转 `3 -> 4`,得到 `4 -> 3`。 - 最后一组:`5` 不足一组,保持原样。 - 最终链表:`2 -> 1 -> 4 -> 3 -> 5`。 通过上述方法,可以高效地实现链表中每 `k` 个节点为一组反转操作。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值