持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情
题目描述
给定 循环单调非递减 列表中的一个点,写一个函数向这个列表中插入一个新元素 insertVal ,使这个列表仍然是循环升序的。
给定的可以是这个列表中任意一个顶点的指针,并不一定是这个列表中最小元素的指针。
如果有多个满足条件的插入位置,可以选择任意一个位置插入新的值,插入后整个列表仍然保持有序。
如果列表为空(给定的节点是 null),需要创建一个循环有序列表并返回这个节点。否则。请返回原先给定的节点。
提示:
示例 1:
输入:head = [3,4,1], insertVal = 2
输出:[3,4,1,2]
解释:在上图中,有一个包含三个元素的循环有序列表,你获得值为 3 的节点的指针,我们需要向表中插入元素 2 。新插入的节点应该在 1 和 3 之间,插入之后,整个列表如上图所示,最后返回节点 3 。
示例 2:
输入: head = [], insertVal = 1
输出: [1]
解释: 列表为空(给定的节点是 null),创建一个循环有序列表并返回这个节点。
示例 3:
输入: head = [1], insertVal = 0
输出: [1,0]
整理题意
题目给定 循环单调非递减 链表中的一个点,要求在该链表中插入一个新元素,新元素值为 insertVal ,需要使得插入后的链表任然是 循环单调非递减链表。
- 这里需要注意题目中描述有不当的地方,“升序”和“非递减”是不同的。
- 该链表为循环链表,也就是首尾是相互连接的。
解题思路分析
- 由于题目给定的是 循环单调非递减链表,说明链表中可能存在相同元素;
- 由于给定的点并非一定为链表的头节点,所以我们需要通过遍历找到该链表首尾相连的地方,由于是非递减链表,所以只需要找到最后一个最大的元素即为链表的尾节点,而尾节点的下一个节点即为头节点;
- 对边界和特殊情况进行判断和处理;
- 然后遍历链表,将元素
insertVal插入即可,即链表的插入操作。
需要注意边界和特殊情况的判断和处理,包括空链表、链表中只有一个元素、链表中存在相同元素等情况的判断和处理。
具体实现
- 首先判断给定节点是否为空,如果链表为空,创建一个节点,值为
insertVal,并让该节点指向自己,返回该节点。 - 如果链表不为空,遍历链表找到链表中的尾节点,也就是找到了链表首尾相连的地方。
在找尾节点时,需要注意链表中是否只存在一个节点,当循环再次回到题目给定的节点时,说明已经遍历完一遍链表了。
- 判断插入的元素是否插在首尾相连处,有两种情况插在首尾相连处:
- 插入值比头节点还要小;
- 插入值比尾节点还要大;
- 如果并非在首尾相连处插入,就遍历链表,找到一个当前节点小于等于当前插入值,当前节点的下一个节点大于等于插入值的位置,将其插入即可。
复杂度分析
- 时间复杂度:,其中
n是链表的节点数。需要遍历链表一次寻找插入节点的位置,插入节点的时间是 。 - 空间复杂度:。
代码实现
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node() {}
Node(int _val) {
val = _val;
next = NULL;
}
Node(int _val, Node* _next) {
val = _val;
next = _next;
}
};
*/
class Solution {
public:
Node* insert(Node* head, int insertVal) {
if(head == NULL){
head = new Node(insertVal);
head->next = head;
return head;
}
Node* res = head;
Node* last;
//找到尾节点
while(1){
//如果链表只有一个元素,或者链表中节点值都相同
if(head->next == res){
last = head;
break;
}
//当前节点值大于下一个节点值
if(head->val > head->next->val){
last = head;
break;
}
head = head->next;
}
//内置函数,插入操作
auto op = [&](Node* temp){
Node* now = new Node(insertVal);
now->next = temp->next;
temp->next = now;
};
//特判插入值大于尾节点值或小于首节点值
if(insertVal <= last->next->val || insertVal >= last->val){
op(last);
return res;
}
//不在链表首尾连接处插入,在链表当中插入
else{
while(1){
//当前节点小于等于当前插入值,下一个节点大于等于插入值
if(head->val <= insertVal && head->next->val >= insertVal){
op(head);
return res;
}
head = head->next;
}
}
}
};
总结
- 该题考察链表的插入操作,具体操作为先更新插入节点的下一个链接的节点
next,再将原链表断开,这样可以避免丢失后面链表的信息,所以需要先记录即将断开处的下一个节点。 - 同时需要注意特殊情况以及边界情况的处理,当链表中只有一个元素或者没有元素时的特殊判断和处理,以及链表中存在多个相同元素时的处理。
- 测试结果:
结束语
你所做的事情,也许暂时看不到结果,但请不要灰心,你并不是没有成长,而是正在扎根。从来没有一蹴而就的成功,只有日复一日的坚持。愿你对每件热爱的事物都能沉淀执着,全力以赴又满载而归。