刷题的日常-排序的循环链表

138 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情

刷题的日常

一天一题,保持脑子清爽

排序的循环链表

来自leetcode每日(2022年6月18日)一题,题意如下:

给定循环单调非递减列表中的一个点,写一个函数向这个列表中插入一个新元素 insertVal ,使这个列表仍然是循环升序的。
给定的可以是这个列表中任意一个顶点的指针,并不一定是这个列表中最小元素的指针。
如果有多个满足条件的插入位置,可以选择任意一个位置插入新的值,插入后整个列表仍然保持有序。
如果列表为空(给定的节点是 null),需要创建一个循环有序列表并返回这个节点。否则。请返回原先给定的节点。

理解题意

通过题目的描述,我们可以得出的信息有如下:

  • 链表是循环链表
  • 链表在某个节点往后是升序的
  • 给定的节点不一定是升序列表中的最小节点,需要我们自己去搜索
  • 给定的链表有可能是空的,如果是空的,返回插入的节点
  • 插入节点之后,链表需要保证仍旧是升序的 做成图的话如下: image.png

做题思路

  • 首先判断传入的列表
    • 如果列表是空的,那么将插入的节点首尾相连,然后返回插入的节点即可
  • 如果列表不是空的,那么这个时候就有三种情况需要判断
    • 插入的值在升序列表中间,即原表中有 大于 插入节点的值,也有 小于 插入节点的值
    • 插入的节点在列表中是最大值,这个时候需要插入列表最大值的后面
    • 插入的节点在列表中是最小值,这个时候需要插入列表最小值的前面
  • 上面的三种情况其实可以简化为两步
    • 插入的值在升序列表中间,那么直接放到中间即可
    • 最大最小值的情况,因为是循环链表,不管是最大最小,直接将插入的值放到原链表的 最小值 前面,逻辑一样成立

代码实现

根据如上分析,我们可以实现代码如下,最大最小值的情况会多扫描一次链表,最多扫描两次,所以时间复杂度为O(n):

public class Solution {
    public Node insert(Node head, int insertVal) {
        Node insNode = new Node(insertVal), tmp;
        if (head == null) {
            insNode.next = insNode;
            return insNode;
        }
        Node root = head;
        Node min = head;
        while (true) {
            if (root.val <= insertVal && root.next.val >= insertVal) {
                tmp = root.next;
                root.next = insNode;
                insNode.next = tmp;
                return head;
            }
            if (root.val < min.val) {
                min = root;
            }
            if (root.next == min) {
                root.next = insNode;
                insNode.next = min;
                return head;
            }
            root = root.next;
        }
    }
}

image.png