题意分析
- 这个题目会给我们两个有序的链表,然后我们需要将两个有序的链表合并,然后得到一个新的有序的链表,返回这个链表的头指针即可。
思路分析
前置知识
- 我们首先观察这两个链表的特点,我们发现这两个链表都是有序的,然后最后合并成一个有序的链表。这个特点其实和我们的归并排序的思想是一样的。归并排序就是先将一个要排序的区间切分成log份,然后可以通过先将小区间排序,然后对于排好序的区间,我们将这两个区间进行合并成一个新的有序的区间,最终合并成一个全部有序的区间。
大家可以结合这个图进行理解,归并排序的时间复杂度为nlogn。这是一种很高效的排序方式。
解法一 C++版
这个题目其实就是一个归并的思想,对于两个有序的区间,我们只需要对他进行一次归并就可以合并这个区间了。具体的方法就是
- 我们先找到两个链表的头指针中更小的作为最终链表的头指针。
- 对两个链表进行遍历,找到更小的那个指针的值作为下一个结点。直到有一个链表到了链表尾部。
- 对没有遍历完的链表继续进行遍历,返回最开始的头节点。
代码如下
- 需要遍历两个链表的每一个结点,所以时间复杂度为O(n+m),n和m分别为两个链表的长度
- 并未开辟新的内存空间,所以空间复杂度为O(1)
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param l1 ListNode类
* @param l2 ListNode类
* @return ListNode类
*/
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
// write code here
// 对链表为空的情况进行判断
if(l1==NULL&&l2==NULL) return NULL;
else if(l1==NULL&&l2!=NULL) return l2;
else if(l1!=NULL&&l2==NULL) return l1;
ListNode *root = new ListNode(-1);
// 在两个链表都不是空的情况下,判断哪个链表的头指针可以作为最终的头指针
if((l1->val)<(l2->val)){
root=l1;
l1=l1->next;
}
else{
root=l2;
l2=l2->next;
}
// 记录下新形成的链表的头结点指针
ListNode *head=root;
// 用一个while对两个链表不断遍历,每次遍历找到更小的那个指针作为下一个指针
while(l1!=NULL&&l2!=NULL){
// 将更小的结点指针作为下一个指针
if((l1->val)>(l2->val)){
root->next=l2;
l2=l2->next;
}else{
root->next=l1;
l1=l1->next;
}
root=root->next;
}
// 退出while的时候,一定是有一个链表为空,再次对两个链表进行遍历
while(l1){
root->next=l1;
l1=l1->next;
root=root->next;
}
while(l2){
root->next=l2;
l2=l2->next;
root=root->next;
}
return head;
}
};解法二 Go语言版
- Go语言具体的思路其实也是一样的。
- 我们先找到两个链表的头指针中更小的作为最终链表的头指针。
- 对两个链表进行遍历,找到更小的那个指针的值作为下一个结点。直到有一个链表到了链表尾部。
- 对没有遍历完的链表继续进行遍历,返回最开始的头节点。
- 代码如下
- 需要遍历两个链表的每一个结点,所以时间复杂度为O(n+m),n和m分别为两个链表的长度
- 并未开辟新的内存空间,所以空间复杂度为O(1)
package main
import . "nc_tools"
/*
* type ListNode struct{
* Val int
* Next *ListNode
* }
*/
/**
*
* @param l1 ListNode类
* @param l2 ListNode类
* @return ListNode类
*/
func mergeTwoLists( l1 *ListNode , l2 *ListNode ) *ListNode {
// write code here
// 特殊情况进行判断
if l1==nil&&l2==nil {
return nil
} else if l1!=nil &&l2==nil{
return l1
}else if l1==nil&&l2!=nil{
return l2
}
// 到了这步说明这两个链表都不是空的了
var root *ListNode
// 寻找出那个链表的头指针适合用来作为最终的头指针
if l1.Val>l2.Val {
root=l2;
l2=l2.Next
}else{
root=l1;
l1=l1.Next
}
head := root
// 对两个链表进行遍历,直到一个链表到了最后
for l1!=nil&&l2!=nil {
if l1.Val>l2.Val {
root.Next=l2
l2=l2.Next
root=root.Next
}else{
root.Next=l1
l1=l1.Next
root=root.Next
}
}
// 对没有遍历完的链表进行继续遍历
for l1!=nil {
root.Next=l1
l1=l1.Next
root=root.Next
}
for l2!=nil {
root.Next=l2
l2=l2.Next
root=root.Next
}
// 返回头指针
return head
}
京公网安备 11010502036488号