持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情
刷题的日常
一天一题,保持脑子清爽
排序的循环链表
来自leetcode每日(2022年6月18日)一题,题意如下:
给定循环单调非递减列表中的一个点,写一个函数向这个列表中插入一个新元素 insertVal ,使这个列表仍然是循环升序的。
给定的可以是这个列表中任意一个顶点的指针,并不一定是这个列表中最小元素的指针。
如果有多个满足条件的插入位置,可以选择任意一个位置插入新的值,插入后整个列表仍然保持有序。
如果列表为空(给定的节点是 null),需要创建一个循环有序列表并返回这个节点。否则。请返回原先给定的节点。
理解题意
通过题目的描述,我们可以得出的信息有如下:
- 链表是循环链表
- 链表在某个节点往后是升序的
- 给定的节点不一定是升序列表中的最小节点,需要我们自己去搜索
- 给定的链表有可能是空的,如果是空的,返回插入的节点
- 插入节点之后,链表需要保证仍旧是升序的
做成图的话如下:
做题思路
- 首先判断传入的列表
- 如果列表是空的,那么将插入的节点首尾相连,然后返回插入的节点即可
- 如果列表不是空的,那么这个时候就有三种情况需要判断
- 插入的值在升序列表中间,即原表中有 大于 插入节点的值,也有 小于 插入节点的值
- 插入的节点在列表中是最大值,这个时候需要插入列表最大值的后面
- 插入的节点在列表中是最小值,这个时候需要插入列表最小值的前面
- 上面的三种情况其实可以简化为两步
- 插入的值在升序列表中间,那么直接放到中间即可
- 最大最小值的情况,因为是循环链表,不管是最大最小,直接将插入的值放到原链表的 最小值 前面,逻辑一样成立
代码实现
根据如上分析,我们可以实现代码如下,最大最小值的情况会多扫描一次链表,最多扫描两次,所以时间复杂度为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;
}
}
}