leetcode刷题日记-【25. K 个一组翻转链表】

74 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情

题目描述

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

 

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]] 输出:[1,1,2,3,4,4,5,6] 解释:链表数组如下: [ 1->4->5, 1->3->4, 2->6 ] 将它们合并到一个有序链表中得到。 1->1->2->3->4->4->5->6 示例 2:

输入:lists = [] 输出:[] 示例 3:

输入:lists = [[]] 输出:[]  

提示:

  • k == lists.length
  • 0 <= k <= 10^4
  • 0 <= lists[i].length <= 500
  • -10^4 <= lists[i][j] <= 10^4
  • lists[i] 按 升序 排列
  • lists[i].length 的总和不超过 10^4

解题思路

  • 给定一个链表,和数字k。将链表按照k个一组进行翻转;
  • 翻转是将这个k个看作一个整体,从前向后整个调转,不是两个间前后调转。
  • 当剩余的链表个数小于k时,则直接返回这个链表,不进行翻转。
  • 要求空间复杂度为 O(1),那么就需要在进行遍历时就将链表进行翻转,而不需要额外采用容器存储。
  • 需要注意的是,链表中引用的都是对象,所以修改一个对象会连带着修改它所关联的其它链表节点

代码实现

public ListNode reverseKGroup(ListNode head, int k) {
    // 记录翻转后的新链表
    ListNode res = new ListNode(0);
    res.next = head;
    // k组链表的起始节点
    // 开始节点的前一个节点
    ListNode prev = res;
    // 结束节点(不包含next)
    ListNode end = res;
    while (end.next != null){
        // 一次遍历k个 加上外部的while一共遍历n*k次
        for (int i = 0; i < k ; i ++){
            if (end == null) {
                // 如果当前剩余的链表节点数小于k,则直接返回k
                return res.next;
            }
            // 因为end是从虚拟节点开始的,所以它应该是next
            end = end.next;
        }
        if (end == null) {
            // 如果当前剩余的链表节点数小于k,则直接返回k
            return res.next;
        }
        // 交换开始的节点 因为pre是从虚拟节点开始的 所以这里的节点需要取next
        ListNode start = prev.next;
        // 用来记录下一个开始节点
        ListNode next = end.next;
        // 设置为null后,相当于给翻转提供终止条件,在翻转时如果遇到值为null则停止翻转(这里都是对象引用,所以start节点一直向后调用next时最终会达到end对象)
        end.next = null;
        // 交换prev和end节点之间的链表
        prev.next = reverseByStart(start);
        start.next = next;
        prev = start;
        end = prev;
    }
    return res.next;

}

/**
 * 翻转start链表 终止条件时start.next为null
 * @param start
 */
private ListNode reverseByStart(ListNode start) {
    // 前一个节点
    ListNode pre = null;
    // 当前节点
    ListNode curr = start;
    while (curr != null){
        // 前后对象置换
        ListNode next = curr.next;
        curr.next = pre;
        pre = curr;
        curr = next;
    }
    return pre;
}
  • k个链表都是升序排列的,将它们合并成一个升序链表
  • 涉及到链表的合并,可以独立成一个小问题,就是两个链表的合并 解题思路