leetcode 链表的合并和分割两道题
Posted Allen9012
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode 链表的合并和分割两道题相关的知识,希望对你有一定的参考价值。
leetcode 链表的合并和分割两道题
1.合并两个有序链表
1.1 题目描述
提示:
1.2 接口函数
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
}
1.3 大致框架
1.3.1 思路分析
- 新建立一个链表,即建立一个头结点
这里我们要有2个指针,分别都指空
- 为什么要一个head,因为要返回头指针
- 为什么要一个tail,因为要方便尾插
- 然后数组上下两两比较,小的就依次放在新链表
比较是用一个
L1
和一个L2
指针分别指向原来两个链表的头节点
l1
指向下一个指针然后新链表的head
不动,tail
指针指向这一个节点,即叫做尾指针的意思
- 不断循环,最后当其中一个链表的L1或L2指针指向NULL时,就停止循环
- 最后将剩下来的一个链表连接在新链表后面就可以了
1.3.2 具体步骤
先要防止传进来的而指针是空的
//注意第一次凡是有空指针也会崩
//如果为空直接返回另外一个就可以了
if(l1==NULL)
{
return l2;
}
if(l2==NULL)
{
return l2;
}
这里,头插最好不要放在while
循环里面,在循环之前解决掉就可以了
if(l1->val<l2->val)
{
head=tail=l1;
l1=l1->next;
}
else
{
head=tail=l2;
l2=l2->next;
}
while循环不断走直到最后走到由一个指针NULL
while(l1&&l2)
{
//取小的尾插到新链表
if(l1->val<l2->val)
{
tail->next=l1;
l1=l1->next;
}
else
{
tail->next=l2;
l2=l2->next;
}
//tail走到新的位置上
tail=tail->next;
}
当由一个为空时把另外一个连到新链表上然后,返回头指针
//l2为空
if(l1)
{
tail->next=l1;
}
//l1为空
if(l2)
{
tail->next=l2;
}
return head;
1.4 具体实现
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
//注意第一次凡是有空指针也会崩
if(l1==NULL)
{
return l2;
}
if(l2==NULL)
{
return l1;
}
struct ListNode* head=NULL;
struct ListNode* tail=NULL;
//第一次不要放在循环里面
if(l1->val<l2->val)
{
head=tail=l1;
l1=l1->next;
}
else
{
head=tail=l2;
l2=l2->next;
}
while(l1&&l2)
{
//取小的尾插到新链表
if(l1->val<l2->val)
{
tail->next=l1;
l1=l1->next;
}
else
{
tail->next=l2;
l2=l2->next;
}
//tail走到新的位置上
tail=tail->next;
}
//l2为空
if(l1)
{
tail->next=l1;
}
//l1为空
if(l2)
{
tail->next=l2;
}
return head;
}
1.5 方法选择
另一个带头节点法:
-
设置一个哨兵位头节点
-
一样的判断步骤,进行尾插
这里不能忘记==
tail->next=NULL;
==避免两个都是空的 -
剩下的步骤同样道理,主要是少一点开始的判断步骤
-
注意最后要处理释放之前的节点
//创建一个哨兵位头节点
struct ListNode* head=NULL;
struct ListNode* tail=NULL;
head =tail=(struct ListNode*)malloc(sizeof(struct ListNode));
tail->next=NULL;//防止两个都是空的,方便尾插
while(l1&&l2)
{
//取小的尾插到新链表
if(l1->val<l2->val)
{
tail->next=l1;
l1=l1->next;
}
else
{
tail->next=l2;
l2=l2->next;
}
tail=tail->next;
}
//l2为空
if(l1)
{
tail->next=l1;
}
//l1为空
if(l2)
{
tail->next=l2;
}
struct ListNode* node=head;
head=head->next;
free(node);
return head;
2. 分割链表
2.1 题目描述
这是遇到的第一道难度为中等的题
本题目来源于leetcode 分割链表
提示:
2.2 接口函数
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* partition(struct ListNode* head, int x){
}
2.3 大致框架
假如给出这样的例子,虽说原题没有要求说顺序不变,但是这里用牛客网的要求做试试看
那么这时我们的答案应该是,因为要求了相对顺序是不能变的,所以最后输出就是这样
2.3.1 思路分析
把小于x的尾插到一个链表,再把大于x的尾插到一个链表,最后连接两个链表
- 创建两个哨兵位的头节点,分别创建对应的头尾指针
- 分别判断假如该节点的值小于给出的x,就尾插到小数链表,反之大的链表
- 当然尾指针要自动跟上,变成尾,走完后会发现大致顺序没有变化
- 最后来链接在一起就ok了,终止条件是原链表走完
2.3.2 具体步骤
按照第一次的思路按部就班地做
出现了问题,提示
struct ListNode* partition(struct ListNode* head, int x){
struct ListNode* lessHead,*lessTail,*greaterHead,*greaterTail;
lessHead=lessTail=(struct ListNode*)malloc(sizeof(struct ListNode));
greaterHead=greaterTail=(struct ListNode*)malloc(sizeof(struct ListNode));
lessTail->next=NULL;
greaterTail->next=NULL;
struct ListNode*cur=head;
while(cur)
{
if(cur->val<x)//只处理<的
{
lessTail->next=cur;
lessTail=lessTail->next;
}
else
{
greaterTail->next=cur;
greaterTail=greaterTail->next;
}
cur=cur->next;
}
//连接两个链表
lessTail->next=greaterHead->next;
head=lessHead->next;
free(lessHead);
free(greaterHead);
return head;
}
这样说明出现问题,就要改进一下
一般时间超限原因是出现死循环
内存超限有时候是因为其他原因导致,这道题不是因为这里超过内存复杂度问题,应该想一下极端情况
这个情况是很难想到的,需要多多体会
我们将 greater 的 next指针置空,这是因为当前节点复用的是原链表的节点,而其 next指针可能指向一个小于 x 的节点,这样就会形成环,我们需要切断这个引用。
正是因为死循环所以才会报错
解决方法就是把最后一个节点置空
//关键
greaterTail->next=NULL;
2.4 具体实现
struct ListNode* partition(struct ListNode* head, int x){
struct ListNode* lessHead,*lessTail,*greaterHead,*greaterTail;
lessHead=lessTail=(struct ListNode*)malloc(sizeof(struct ListNode));
greaterHead=greaterTail=(struct ListNode*)malloc(sizeof(struct ListNode));
lessTail->next=NULL;
greaterTail->next=NULL;
struct ListNode*cur=head;
while(cur)
{
if(cur->val<x)//只处理<的
{
lessTail->next=cur;
lessTail=lessTail->next;
}
else
{
greaterTail->next=cur;
greaterTail=greaterTail->next;
}
cur=cur->next;
}
//连接两个链表
lessTail->next=greaterHead->next;
//关键
greaterTail->next=NULL;
head=lessHead->next;
free(lessHead);
free(greaterHead);
return head;
}
小结:
这道题其实还有多种解法,有兴趣可以看一下多题解
这篇题目就到此为止,大家觉得有收获就请一键三连,谢谢
以上是关于leetcode 链表的合并和分割两道题的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode Algorithm 21. 合并两个有序链表