Java每日一题——>剑指 Offer II 029. 排序的循环链表

Posted stormzhuo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java每日一题——>剑指 Offer II 029. 排序的循环链表相关的知识,希望对你有一定的参考价值。

这是LeetCode上的 [029,排序的循环链表],难度为 [中等]

题目

给定循环单调非递减列表中的一个点,写一个函数向这个列表中插入一个新元素 insertVal ,使这个列表仍然是循环升序的。

给定的可以是这个列表中任意一个顶点的指针,并不一定是这个列表中最小元素的指针。

如果有多个满足条件的插入位置,可以选择任意一个位置插入新的值,插入后整个列表仍然保持有序。

如果列表为空(给定的节点是 null),需要创建一个循环有序列表并返回这个节点。否则。请返回原先给定的节点。

示例 :

输入:head = [3,4,1], insertVal = 2
输出:[3,4,1,2]
解释:在上图中,有一个包含三个元素的循环有序列表,你获得值为 3 的节点的指
针,我们需要向表中插入元素 2 。新插入的节点应该在 1 和 3 之间,插入之后,整
个列表如下图所示,最后返回节点 3 。

题解

为了使插入的新结点的循环链表仍然是排序的,新结点的前一个结点的值应该比新结点的值小,后一个结点的值应该比新结点的值大,但是有两种特殊情况需要处理

  • 如果新结点的值比链表中已有的最大值还有大,此时它大于它的前一个结点的值(最大值),且还大于后一个结点的值(最小值)
  • 如果新结点的值比链表中已有的最小值还要小,此时它小于它的前一个结点的值(最大值),,且还小于后一个结点的值(最小值)

综上,两种情况都是新的结点插入到最大值和最小值之间

因此,需要遍历循环链表,每次找到相邻的两个结点进行判断,会有三种情况

如果找不到相邻的两个结点(循环链表为空或循环链表只有一个结点)

  • 当循环链表为空时,让新结点插入循环链表中,新结点指向自己
  • 当循环链表只有一个结点时,让循环链表原有结点指向新结点,新结点指向原有结点

如果前一个结点的值比代插入的的值小并且后一个结点的值比代插入的值大,那么就将新结点插入这两个结点之间

如果找不到符合条件的两个结点,即待插入的值大于链表中已有的最大值或小于已有的最小值,那么就将新结点插入最大值和最小值之间

代码实现

class Solution 

     public Node insert(Node head, int insertVal) 
        // 创建一个新结点,值为插入的值
        Node newNode = new Node(insertVal);
        // 当循环链表为空时
        if (head == null) 
            // 新结点作为头结点,唯一的结点
            head = newNode;
            // 新结点指向自己
            head.next = head;
        // 当循环链表只有一个结点时
         else if (head.next == null) 
            // 原有结点指向新结点
            head.next = newNode;
            // 新结点指向原有结点
            newNode.next = head;
        // 当循环链表大于等于两个结点时
         else 
            insertCore(head, newNode);
        
        return head;
    

    public void insertCore(Node head, Node newNode) 
        // 遍历时当前结点,初始为头结点
        Node currNode = head;
        // 遍历时当前结点的下一个结点,初始为头结点的下一个结点
        Node nextNode = head.next;
        // 记录循环链表的最大值的结点,初始为头结点
        Node maxNode = head;
       /* 遍历循环链表,循环终止条件分为两种情况
       * 若当前结点的值小于新结点的值且当前结点的下一个结点的值大于新结点的值时,循环终止
       * 若当前结点的下一个结点是头结点时,说明已遍历完链表,循环终止*/
        while (!(currNode.val <= newNode.val && nextNode.val >= newNode.val) && nextNode != head) 
            // 重置当前结点,让当前结点的下一个结点作为当前结点
            currNode = nextNode;
            // 重置当前结点的下一个结点,让当前结点的下一个结点的下一个结点作为当前结点的下一个结点
            nextNode = nextNode.next;
            /* 由于最大值的结点初始为头结点,而头结点不一定是最小的,故循环链表的尾结点也不一定是最大的
            * 所以每次都需要比较当前结点和最大值结点的大小*/
            if (currNode.val >= maxNode.val) 
                maxNode = currNode;
            
        
        // 循环终止的第一种情况,当前结点的值小于新结点的值且当前结点的下一个结点的值大于新结点的值
        if (currNode.val <= newNode.val && nextNode.val >= newNode.val) 
            // 当前结点指向新结点
            currNode.next = newNode;
            // 新结点指向当前结点的下一个结点
            newNode.next = nextNode;
        /* 循环终止的第二种情况,遍历完链表也找不到满足关系的两个相邻结点,
            即新结点的值比最大值还大或比最小值还小*/
         else 
            // 新结点指向最大值结点的下一个结点
            newNode.next = maxNode.next;
            // 最大值的结点指向新结点
            maxNode.next = newNode;
        
    

复杂度分析

假设循环链表的结点数为n

时间复杂度:

需要遍历链表,故时间复杂度为O(n)

空间复杂度:

只声明了几个结点,故空间复杂度为O(1)

以上是关于Java每日一题——>剑指 Offer II 029. 排序的循环链表的主要内容,如果未能解决你的问题,请参考以下文章

Java每日一题——>剑指 Offer II 035. 最小时间差(三解,蛮力,排序,哈希)

Java每日一题——> 剑指 Offer II 028. 展平多级双向链表

Java每日一题——>剑指 Offer II 027. 回文链表

Java每日一题——>剑指 Offer II 030. 插入删除和随机访问都是 O 的容器

Java每日一题——>剑指 Offer II 034. 外星语言是否排序

Java每日一题——>剑指 Offer II 034. 外星语言是否排序