创建一个空头节点,ListNode res = new ListNode(0),p = res(这个要记下来),用于将两个链表合并到这个节点后面。创建一个指针p指向这个空头节点,用于指向这个空链表的最后一个节点。通过比较L1和L2链表节点的值,哪个节点值小,就将空头节点的next指向哪个节点。下一步,比如L1节点的值更小,空头节点指向它以后,L链表指针往后移动一个。继续比较,直到这两个链表中有一个链表遍历完了,剩下没遍历完的链表接在新链表后面。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
pre, cur = head, head
for _ in range(1, k):
cur = cur.next
while cur.next != None:
pre = pre.next
cur = cur.next
return pre
伪头节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
p = l1
q = l2
res = ListNode(0)
tmp = res
while p and q:
if p.val >= q.val:
tmp.next = q
q = q.next
else:
tmp.next = p
p = p.next
tmp = tmp.next
tmp.next = p if p else q
return res.next
共以下 99 个回答
呜呜打卡
复杂度O(n+m),思路跟各位大佬差不多,就是直接新建一个头指针,然后直接插入
打卡
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode res = new ListNode(-1);
ListNode tail = res;
}
时间复杂度O(n)
空间复杂度O(1)
思路:和归并排序的额最后一步类似
时间复杂度:O(n + m)
空间复杂度:O(1)
没啥技巧,纯输出:
c++
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* dnode=new ListNode(0);
ListNode* cur=dnode;
while(l1!=NULL&&l2!=NULL){
if(l1->val>=l2->val){
cur->next=l2;
l2=l2->next;
cur=cur->next;
}else{
cur->next=l1;
l1=l1->next;
cur=cur->next;
}
}
if(l1NULL&&l2!=NULL){
cur->next=l2;
}
if(l1!=NULL&&l2NULL){
cur->next=l1;
}
return dnode->next;
}
};
”’java
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//两个指针
};
时间复杂度O(n)
空间复杂度O(1)
双指针交替前进
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode res = new ListNode(0) ,curr = res;
while(l1!= null && l2!= null) {
if(l1.val <= l2.val) {
curr.next = l1;
curr = curr.next;
l1 = l1.next;
} else {
curr.next = l2;
curr = curr.next;
l2 = l2.next;
}
}
if (l1 null) {
curr.next = l2;
} else if (l2 null) {
curr.next = l1;
}
return res.next;
}
}
思路:使用双指针和虚拟头结点结合,比较两个链表值的大小,然后移动临时指针
代码
时间复杂度:O(n)
空间复杂度:O(n)
时间复杂度O(n)
空间复杂度O(1)
结果链表,用双指针表示,一个头指针,一个更新指针,
循环比较两个链表,把两个链表中小的值,逐个更新进结果链表,直到其中一个链表为空,则把另外一个链表直接放结果链表后面
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 null) return l2;
if (l2 null) return l1;
ListNode temp = new ListNode(0),curr = temp;
while (l1 != null && l2!=null){
if (l1.val >= l2.val){
curr.next = l2;
l2 = l2.next;
}else{
curr.next = l1;
l1 = l1.next;
}
curr = curr.next;
}
// l1为空,代表没有可以比较的值了,比如l1有三个元素,l2有四个元素,l1在某些比较情况下最后会指向空,这种情况就将curr指向l2剩余的就好了,因为l2时递增排序的
curr.next = l1 != null ? l2 : l1;
return temp.next;
}
}
时间复杂度:O(n+m),因为需要遍历两个链表。空间复杂度:O(1)
时间复杂度O(N), 空间复杂度O(N)
时间复杂度O(n)
空间复杂度O(l1+l2)
由于l1,l2是递增的,因此使用双指针遍历两链表,根据l1.val与l2.val的大小确定添加节点的顺序,交替进行直到遍历完成
创建空链表,引入伪头节点
或者递归
““java
class Solution{
public ListNode mergeTwoLists(ListNode l1, ListNode l2){
ListNode merge=new ListNode(0);
ListNode temp = merge;
while(l1!=null&&l2!=null){
if(l1.val<l2.val){
temp.next=l1;
l1=l1.next;
} else{
temp.next=l2;
l2=l2.next;
|
temp.next=l1null?l2:l1;
return merge.next;
}
}
定义一个虚拟头节点,可避免处理空指针的情况
时间复杂度:O(m+n)
空间复杂度:O(1)
python3实现
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
cur = dum = ListNode(0)
while l1 and l2:
if l1.val < l2.val:
cur.next, l1 = l1, l1.next
else:
cur.next, l2 = l2, l2.next
cur = cur.next
cur.next = l1 if l1 else l2
return dum.next
设置辅助节点
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode merge = new ListNode(0);
ListNode temp = merge;
}
用一个虚拟头节点,避免处理空指针的情况
类似于”拉拉链“,l1, l2 就相当于拉链两侧的锯齿,指针 cur 就好像拉链的拉索,将两个有序链表合并
Time:O(M+N)
Space:O(1)
合并
时间复杂度:O(m + n)。
空间复杂度:O(1)。
使用辅助节点避免频繁判断null
解题思路
创建一个空头节点,ListNode res = new ListNode(0),p = res(这个要记下来),用于将两个链表合并到这个节点后面。创建一个指针p指向这个空头节点,用于指向这个空链表的最后一个节点。通过比较L1和L2链表节点的值,哪个节点值小,就将空头节点的next指向哪个节点。下一步,比如L1节点的值更小,空头节点指向它以后,L链表指针往后移动一个。继续比较,直到这两个链表中有一个链表遍历完了,剩下没遍历完的链表接在新链表后面。
代码
“`cpp
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode *res = new ListNode(0),*p = res;
//如果某个链表为空链表,则直接返回另外一个链表
if(!l1) return l2;
if(!l2) return l1;
while(l1 && l2)
{
l1->val > l2->val ?(p->next = l2,l2 = l2->next):(p->next = l1,l1 = l1->next);
p = p->next;
}
if(!l1)
{
p->next = l2;
return res->next;
}
else
{
p->next = l1;
return res->next;
};
时间复杂度o(m+n)
空间复杂度o(1)
创建辅助节点
“`c++
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode *t = new ListNode(-1);
t->next = NULL;
ListNode *cur = t;
while(l1 && l2){
if(l1->val <= l2->val){
cur->next = l1;
l1 = l1->next;
}else{
cur->next = l2;
l2 = l2->next;
}
cur = cur->next;
}
if(l1) cur->next = l1;
else cur->next = l2;
};
“`
注意使用头节点辅助节点
复杂度分析:
时间复杂度: O(M+N) : M,N 分别为链表 l1,l2 的长度,合并操作需遍历两链表。
空间复杂度: O(1) : 节点引用 mergeList, temp使用常数大小的额外空间。
用递归
时间复杂度O(M+N)
空间复杂度O(1)
“`C++
class Solution {
//实现
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
};
“`
时间复杂度:O(m+n)
空间复杂度:O(1)
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//新建一个链表对象,用于存放merge后的链表结果
ListNode mergeListNode = new ListNode();
ListNode temp = mergeListNode;
//非空判断
if (l1null&&l2null){
return null;
}
while(l1!=null && l2!=null) {
if (l1.val < l2.val) {
mergeListNode.next = l1;
mergeListNode = mergeListNode.next;
l1 = l1.next;
} else {
mergeListNode.next = l2;
mergeListNode = mergeListNode.next;
l2 = l2.next;
}
}
if (l2!=null){
mergeListNode.next = l2;
}else if (l1!=null){
mergeListNode.next = l1;
}
return temp.next;
}
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//新建一个链表对象,用于存放merge后的链表结果
ListNode mergeListNode = new ListNode();
ListNode temp = mergeListNode;
//非空判断
if (l1null&&l2null){
return null;
}
while(l1!=null && l2!=null) {
if (l1.val < l2.val) {
mergeListNode.next = l1;
mergeListNode = mergeListNode.next;
l1 = l1.next;
} else {
mergeListNode.next = l2;
mergeListNode = mergeListNode.next;
l2 = l2.next;
}
}
if (l2!=null){
mergeListNode.next = l2;
}else if (l1!=null){
mergeListNode.next = l1;
}
return temp.next;
}
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//新建一个链表对象,用于存放merge后的链表结果
ListNode mergeListNode = new ListNode();
ListNode temp = mergeListNode;
//非空判断
if (l1null&&l2null){
return null;
}
while(l1!=null && l2!=null) {
if (l1.val < l2.val) {
mergeListNode.next = l1;
mergeListNode = mergeListNode.next;
l1 = l1.next;
} else {
mergeListNode.next = l2;
mergeListNode = mergeListNode.next;
l2 = l2.next;
}
}
if (l2!=null){
mergeListNode.next = l2;
}else if (l1!=null){
mergeListNode.next = l1;
}
return temp.next;
}
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//新建一个链表对象,用于存放merge后的链表结果
ListNode mergeListNode = new ListNode();
ListNode temp = mergeListNode;
//非空判断
if (l1null&&l2null){
return null;
}
while(l1!=null && l2!=null) {
if (l1.val < l2.val) {
mergeListNode.next = l1;
mergeListNode = mergeListNode.next;
l1 = l1.next;
} else {
mergeListNode.next = l2;
mergeListNode = mergeListNode.next;
l2 = l2.next;
}
}
if (l2!=null){
mergeListNode.next = l2;
}else if (l1!=null){
mergeListNode.next = l1;
}
return temp.next;
}
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//新建一个链表对象,用于存放merge后的链表结果
ListNode mergeListNode = new ListNode();
ListNode temp = mergeListNode;
//非空判断
if (l1null&&l2null){
return null;
}
while(l1!=null && l2!=null) {
if (l1.val < l2.val) {
mergeListNode.next = l1;
mergeListNode = mergeListNode.next;
l1 = l1.next;
} else {
mergeListNode.next = l2;
mergeListNode = mergeListNode.next;
l2 = l2.next;
}
}
if (l2!=null){
mergeListNode.next = l2;
}else if (l1!=null){
mergeListNode.next = l1;
}
return temp.next;
}
打卡
时间复杂度O(m+n),空间复杂O(1)
时间复杂度:O(m+n)
空间复杂度:O(1)
打卡
双指针
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
}
时间复杂度:O(n)
空间复杂度:O(1)
顺序遍历,虚拟头节点 O(n+m) O(1)
C++实现 时间复杂度O(n) 空间复杂度O(1) 创建一个虚拟头结点然后利用双指针的思想比较两个链表中数据较小的结点将它加入虚拟节点后然后重复下去
“`java
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode merge = new ListNode(0);\\建立一个辅助节点
ListNode temp = merge;
}
创建伪头节点,判断if(l1.val >= l2.val)则将l2.val添加进链表再将l2向前走一步,反之前进l1
定义一个虚拟头节点dummy,使用cur始终指向合并链表的头节点。
记录合并链表的header,定义一个temp指针,接下来往temp指针后依次添加l1/l2中更小的节点即可,时间复杂度O(m+n),空间复杂度O(1)
合并到一个新链表,此法比较简单,也可在将两个链表合并到其中一个链表,能节省空间复杂度
剑指 Offer 25. 合并两个排序的链表
依次比较大小
时间复杂度:O(m+n)
空间复杂度:O(1)
C++实现
时间复杂度 O(m+n),空间 O(m+n),主要是弄了个新链表用新节点存放合并结果,但是也可以用原节点存放结果
直接遍历
时间:O(m+n)
空间:O(1)
c++
使用双指针,每个指针指向一个链表的头节点。不断比较两个指针的值,将小节点的放入到新构建的链表,直到遍历完其中一个链表。然后把剩下的链表接在构建好的链表的尾部即可。
TC: O(n)
SC: O(1)
“`c#
public ListNode MergeTwoLists(ListNode l1, ListNode l2) {
ListNode head = new ListNode(0);
ListNode temp = head;
“`
循环的判断条件,头节点的设置与保存
不管怎么样,也是自己写出来的。啊啊啊
【时间O(m+n),空间O(1)】
从头比较两个链表节点
将小的接到cur节点后面
将剩余链表接到cur节点后面
返回头结点
时间复杂度:O(m+n)
空间复杂度:O(1)
1、先创建合并之后的头结点以及头结点的next结点temp
2、在两个待合并链表头结点非空的条件下循环
3、哪个头结点值小,则将temp的next节点指向该节点,并该头结点往后移
4、判断一次大小后,将temp结点往后移
5、循环结束后,用三元运算符将temp的next结点指向未遍历到结尾的链表的头结点
有难度
时间复杂度:O(m + n) m为l1的节点个数,n为l2的节点个数
空间复杂度:O(1)
C++
执行用时:
16 ms
内存消耗:
18.7 MB
合并两个排序的链表:
采用双指针的方式:
首先创建一个新的头节点,接着判断被排序链表的头节点的值的大小关系
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
if not l1:
return l2
if not l2:
return l1
res=ListNode(0)
cur=res
while l1 and l2:
if l1.val<l2.val:
cur.next=l1
l1=l1.next
else:
cur.next=l2
l2=l2.next
cur=cur.next
if l1:
cur.next=l1
else:
cur.next=l2
return res.next
”’
1 分别判断l1和l2两个链表是否为空,如果一方为空,则返回另一方即可
2 设立一个头结点res,用cur指针,指向头结点
3接着是存在的一个阶段,就是l1和l2都不为空,互相比对l1和l2的值,哪一方小,指针的下一个对象就是哪一方,在此基础上,哪一方的值被后面的那个值替代,指针相当于原先这个位置走过了,接下来走到下一个位置,即cur=cur.next
4进入下一个阶段,那就是一方比另一方短,如果上个阶段走完还有的话,换句话说,有一个链表已经为空,在此基础上,cur的下一个对象就是不为空的那个
5指针走完,新的节点已经生成,忽略我刚刚加上的头结点res,选择res.next
时间复杂度O(n),空间复杂度O(1)
”’
代码:
我真笨,提交了5次才AC
思路分析:
1.首先创建一个虚拟节点(dummy),并用变量p指向它。这个虚拟节点将作为合并后的链表的头部。
2.创建两个指针p1和p2,分别指向两个输入链表l1和l2的头节点。
3.使用while循环,只要p1和p2都不为空,就进行以下操作:
4.如果p1的值大于p2的值,说明p2所指向的节点应该排在当前节点之后,因此将p2所指向的节点连接到p的后面,并将p2指针向后移动一位。否则,将p1所指向的节点连接到p的后面,并将p1指针向后移动一位。
5.最后,将p指针向后移动一位,准备连接下一个节点。
6.当其中一个链表遍历完毕后,可能还有剩余节点。此时,将剩余链表的所有节点直接连接到p的后面。
7.最后,返回虚拟节点dummy的下一个节点,即合并后的链表的头节点。
时间复杂度为O(m+n),m和n分别是两个输入链表的长度,因为我们需要遍历两个链表的所有节点。
时间复杂度:O(m+n)
空间复杂度:O(1)
思路:新建一个头节点,比较两个排序链表大小,小的连到新节点后,直到一个链表遍历完,将另一个链表剩余部分全部连接到新链表中
复杂度:时间复杂度O(m+n)空间复杂度O(1)
“`C++
class Solution {
public:
// 递归写法
// 时间复杂度 O(N + M),两个链表节点数和
// 空间复杂度 O(N + M),每次递归会新开辟栈空间
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;
}
};
};
class Solution {
public:
// 迭代写法
// 时间复杂度 O(N + M),两个链表节点数和
// 空间复杂度 O(1)
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* dummyHead = new ListNode(0);
ListNode* cur = dummyHead;
};
“`
C++实现
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1 NULL) return l2;
if(l2 NULL) return l1;
ListNode* newlist = new ListNode(0);
ListNode* tmp = newlist;
while(l1 && l2 ){
if(l1->val <= l2->val){
tmp->next = l1;
l1 = l1->next;
}
else{
tmp->next = l2;
l2 = l2->next;
}
tmp = tmp->next;
}
};
时间复杂度:O(m+n) 空间复杂度:O(m+n)
时间复杂度:O(n+m),空间复杂度:O(1)
c++代码val){
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* dummy = new ListNode(-1);
ListNode* p1 = l1, p2 = l2;
ListNode p = dummy;
while(p1!=nullptr&&p2!=nullptr){
if(p1->val
p->next = p1;
p1 = p1->next;
}
else{
p->next = p2;
p2 = p2->next;
}
p = p->next;
}
if(p1!=nullptr){
p->next = p1;
}
if(p2!=nullptr){
p->next = p2;
}
return dummy->next;
}
};
c++实现
ListNode* phead = new ListNode(-1);
ListNode* pre = phead;
while(l1!=NULL&&l2!=NULL)
{
if(l1->val>l2->val)
{
pre->next = l2;
l2 = l2->next;
}
else
{
pre->next = l1;
l1 = l1->next;
}
pre = pre->next;
}
pre->next = l1NULL?l2:l1;
return phead->next;
c++实现
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1 NULL){
return l2;
}
if(l2 NULL){
return l1;
}
// 创建一个新的链表
ListNode * mergeList = new ListNode;
ListNode * cur = mergeList;
while(l1 && l2){
if(l1->val < l2->val){
cur->next = l1;
l1 = l1->next;
}
else{
cur->next = l2;
l2 = l2->next;
}
cur = cur->next;
}
cur->next = l1 NULL ? l2 : l1;
return mergeList->next;
}
};
时间复杂度O(M+N),分别是两个链表的长度
空间复杂度O(M+N).
思路
l1 == null那么直接返回l2,如果l2 == null那么直接返回l1l1.val < l2.val那么说明,这个位置应该是l1,但注意,下一个位置可能是l1.next,也可能是l2,因此我们这层递归return的应该是l1,然后它的next是l1.next和l2比较的结果。代码
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode newList=new ListNode(-1);
//注意要设置一个指针!!不能把链表头节点向后移动 把指针向后移动
ListNode p=newList;
}
c实现val){
struct ListNode mergeTwoLists(struct ListNode l1, struct ListNode l2){
if(l1NULL)
return l2;
if(l2NULL)
return l1;
struct ListNode root,tail,p=l1,q=l2;
root=(struct ListNode)malloc(sizeof(struct ListNode));
root->next=NULL;
tail=root;
while(p&&q){
struct ListNode *l; if(p->val
l=p;
p=p->next;
}
else{
l=q;
q=q->next;
}
l->next=NULL;
tail->next=l;
tail=l;
}
if(p){
tail->next=p;
}
if(q){
tail->next=q;
}
return root->next;
}
先创建一个虚拟头节点,并让一个指针指向虚拟头节点,如果list1中元素小于list2就把list1链上,否则链上list2。
时间复杂度:O(n+m),空间复杂度:O(1)
“`c++
// c++实现
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* dummy = new ListNode(0);
};
c++ 实现
java语言
时间复杂度为n,空间复杂度为1,。
思路:使用双指针的方式,使用一个辅助链表head,并设立条件,当l1与l2相等时,让merger=l2。逐个遍历l1与l2中的值,如果l1>=l2,则让tmp=l2,且让l2的指针和head的指针指向下一位,反之亦然。最后返回辅助链表的下一位。
class Solution{
public ListNode mergeTowLists(ListNode l1,ListNode l2){
ListNode merge=new ListNode(0);
ListNode temp=merge;
while(l1!=null&&l2!=null){
if(l1.val<l2.val){
temp.next=l1;
l1=l1.next;
}else{
temp.next=l2;
l2=l2.next;
}
temp=temp.next;
}
temp.next=l1null ?l2:l1;
return merge.next;
}
}
时间复杂度:O(n+m)
空间复杂度:O(1)
“`c++ /**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
/*
定义一个头节点用来接收合并的链表,
同时遍历两个链表,头节点指向当前节点小的
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* ans = new ListNode(-1);
ListNode* cur1 = l1,*cur2 = l2,*ret = ans;
while(cur1 && cur2)
{
if(cur2->val < cur1->val)
{
ret->next = cur2;
cur2 = cur2->next;
}
else
{
ret->next = cur1;
cur1 = cur1->next;
}
ret = ret->next;
}
ret->next = cur1==NULL?cur2:cur1;
return ans->next;
}
};
这里是Ming的打卡:
涉及了增删改,那我们拾起好习惯:建立虚拟头结点,将两个链表统统收入,具体每一个在代码里有注解
思想:建立一个头结点,然后设置双指针,分别遍历两个链表,较小(或等于)的元素先插入新链表;最后处理未能插入的剩余链表节点
时间复杂度:O(m+n) 空间复杂度:O(1)
比较容易错的点是保证新生成的链表最后节点为null