将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
思路1:利用stack模板
代码:
#include <iostream>
#include <stack>
using namespace std;
int main(){
int a,b;
int i= 0;
stack<int>st1,st2,st3;
while( scanf("%d->",&a)){
st1.push(a);
}
getchar();
while( scanf("%d->",&a)){
st2.push(a);
}
while(!st1.empty()&&!st2.empty())
{
a = st1.top();
b = st2.top();
if(a<b){
st3.push(b);
st2.pop();
}else if (a==b)
{
st3.push(b);
st1.pop();
st2.pop();
}else{
st3.push(a);
st1.pop();
}
}
if (!st1.empty())
{
st3.push(st1.top());
st1.pop();
}
if (!st2.empty())
{
st3.push(st2.top());
st2.pop();
}
while (!st3.empty())
{
cout<<st3.top()<<"->";
st3.pop();
}
cout<<"null"<<endl;
}
结果:
1->2->4,1->3->4
1->2->3->4->null
思路2:采用数据结构的链表,定义一个指向头节点的Lc,和一个指向尾部节点的pc,属于常规的暴力破解。
#include<malloc.h>
#include<iostream>
using namespace std;
#define OVERFLOW -2
typedef struct Node{
int data;
struct Node *next;
}Node,*LinkList;
int InitList(LinkList &L){
L = (LinkList)malloc(sizeof(Node));
if(!L)
exit(OVERFLOW);
L->next = NULL;
return 1;
}
void CreatList(LinkList &L, int n){
LinkList p,r;
r = L;
int a;
for(int i = 0; i < n; i++){
p = (LinkList)malloc(sizeof(Node));
scanf("%d",&a);
p->data = a;
r->next = p;
r = p;
}
r->next = NULL;
}
void PrintList(LinkList &L){//输出单链表
LinkList q;
q = L->next;
while(q){
printf("%d ",q->data);
q = q->next;
}
}
void Combine(LinkList La, LinkList Lb, LinkList Lc){
LinkList pa,pb,pc;
pa = La->next;
pb = Lb->next;
Lc = pc = La;
while(pa && pb){
if(pa->data <= pb->data){
pc->next = pa;
pc = pa;
pa = pa->next;
}
else{
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
pc->next = pa? pa:pb;
free(Lb);
PrintList(Lc);
}
int main(){
int m,n;
LinkList LA,LB;
InitList(LA);
InitList(LB);
cout<<"Enter the number of La"<<endl;
cin>>m;
CreatList(LA,m);
cout<<"Enter the number of Lb"<<endl;
cin>>n;
CreatList(LB,n);
cout<<endl;
cout<<"the number is La"<<endl;
cout<<"-----------------------"<<endl;
PrintList(LA);
cout<<endl;
cout<<"the number is Lb"<<endl;
cout<<"-----------------------"<<endl;
PrintList(LB);
cout<<"merge La and Lb"<<endl;
LinkList Lc;
InitList(Lc);
Combine(LA,LB,Lc);
return 0;
}
思路3:暴力破解的递归版
也就是说,两个链表头部值较小的一个节点与剩下元素的 merge
操作结果合并。
算法
我们直接将以上递归过程建模,同时需要考虑边界情况。
如果 l1 或者 l2 一开始就是空链表 ,那么没有任何操作需要合并,所以我们只需要返回非空链表。否则,我们要判断 l1 和 l2 哪一个链表的头节点的值更小,然后递归地决定下一个添加到结果里的节点。如果两个链表有一个为空,递归结束。
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if (l1 == nullptr) {
return l2;
} else if (l2 == nullptr) {
return l1;
} else if (l1->val < l2->val) {
l1->next = mergeTwoLists(l1->next, l2);
return l1;
} else {
l2->next = mergeTwoLists(l1, l2->next);
return l2;
}
}
复杂度分析
时间复杂度:O(n + m),其中 n 和 m 分别为两个链表的长度。因为每次调用递归都会去掉 l1 或者 l2 的头节点(直到至少有一个链表为空),函数 mergeTwoList 至多只会递归调用每个节点一次。因此,时间复杂度取决于合并后的链表长度,即 O(n+m)。
空间复杂度:O(n + m),其中 n 和 m 分别为两个链表的长度。递归调用 mergeTwoLists 函数时需要消耗栈空间,栈空间的大小取决于递归调用的深度。结束递归调用时 mergeTwoLists 函数最多调用 n+m次,因此空间复杂度为 O(n+m)。
思路4:迭代
思路
我们可以用迭代的方法来实现上述算法。当 l1 和 l2 都不是空链表时,判断 l1 和 l2 哪一个链表的头节点的值更小,将较小值的节点添加到结果里,当一个节点被添加到结果里之后,将对应链表中的节点向后移一位。
算法
首先,我们设定一个哨兵节点 prehead ,这可以在最后让我们比较容易地返回合并后的链表。我们维护一个 prev 指针,我们需要做的是调整它的 next 指针。然后,我们重复以下过程,直到 l1 或者 l2 指向了 null :如果 l1 当前节点的值小于等于 l2 ,我们就把 l1 当前的节点接在 prev 节点的后面同时将 l1 指针往后移一位。否则,我们对 l2 做同样的操作。不管我们将哪一个元素接在了后面,我们都需要把 prev 向后移一位。
在循环终止的时候, l1 和 l2 至多有一个是非空的。由于输入的两个链表都是有序的,所以不管哪个链表是非空的,它包含的所有元素都比前面已经合并链表中的所有元素都要大。这意味着我们只需要简单地将非空链表接在合并链表的后面,并返回合并链表即可。
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* preHead = new ListNode(-1);
ListNode* prev = preHead;
while (l1 != nullptr && l2 != nullptr) {
if (l1->val < l2->val) {
prev->next = l1;
l1 = l1->next;
} else {
prev->next = l2;
l2 = l2->next;
}
prev = prev->next;
}
// 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
prev->next = l1 == nullptr ? l2 : l1;
return preHead->next;
}
因上求缘,果上努力~~~~ 作者:别关注我了,私信我吧,转载请注明原文链接:https://www.cnblogs.com/BlairGrowing/p/12814803.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?