目录
题目1:合并两个有序链表
题目2:分割链表
题目3:随机链表的复制
“单链表leetcode刷题/上”的链接:https://blog.csdn.net/2302_80297338/article/details/140409360?spm=1001.2014.3001.5501
题目1:合并两个有序链表
解题思路:
创建一个新链表,比较两个原链表的结点val值大小,小的尾插到新链表中,然后比较当前结点val小的链表中的下一个结点和当前结点val大的链表的同一结点。即遍历比较两个原链表每个结点的大小,小的尾插到新链表中,直到一个原链表已经全部遍历完结束。然后将还有一个原链表的剩余结点直接尾插到新链表后面,题目解决。
代码:
typedef struct ListNode listnode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
//小的就尾插在后面
//一个为空,以及两个都是空的情况
if(list1==NULL)
{
return list2;
}
if(list2==NULL)
{
return list1;
}
//全都不为空的情况
listnode* l1,*l2;
l1=list1;
l2=list2;
listnode* newhead,*newtail;
newhead=newtail=(listnode*)malloc(sizeof(listnode)); //创造一个头结点,作为新链表的头
while(l1&&l2)
{
if(l1->val<l2->val)
{
newtail->next=l1;
l1=l1->next;
}
else
{
newtail->next=l2;
l2=l2->next;
}
newtail=newtail->next;
}
if(l2)//l2还有值
{
newtail->next=l2;
}
if(l1)
{
newtail->next=l1;
}
listnode* ret=newhead->next;
free(newhead);
newhead=NULL;
return ret;
}
代码讲解:
为了方便,笔者通过typedef将struct ListNode类型变为了listnode。
情况1:list1、list2有一个是空链表。
情况2:list1、list2两者都是空链表。
情况3:list1、list2两者都不是空链表。
针对情况1,可以使用两个if语句,如果某者为空,就直接返回不为空的链表。
针对情况2,情况1的代码即可有效解决。
针对情况3,整体思路上文已经解析完毕。在开辟完newhead这个结点后,理应将它free置空,防止内存泄露的出现。
题目2:分割链表
解题思路:
开辟两个新链表,一个专门用来存比x小的值,一个专门用来存比x大于或等于的值。再创建一个指针pcur,遍历原链表。
遍历完原链表以后,让大的新链表的尾元结点的next置为NULL,然后将小的链表和大的链表链接起来。
最后对开辟的两个指针进行free操作,最后返回结果。
代码:
typedef struct ListNode listnode;
struct ListNode* partition(struct ListNode* head, int x){
if(head==NULL)
{
return head;
}
listnode* smallhead,*smalltail;
listnode* largehead,*largetail;
listnode* pcur = head;
smallhead=smalltail=(listnode*)malloc(sizeof(listnode));
largehead=largetail=(listnode*)malloc(sizeof(listnode));
while(pcur)
{
//两种尾插
if(pcur->val<x)
{
smalltail->next=pcur;
smalltail=smalltail->next;
}
else
{
largetail->next=pcur;
largetail=largetail->next;
}
pcur=pcur->next;
}
largetail->next=NULL;
smalltail->next=largehead->next;
listnode* ret=smallhead->next;
free(smallhead);
free(largehead);
return ret;
}
代码讲解:
本题有使用到头节点的思想,两个新链表的开辟,开辟的都是头节点。后续的数据全都通过尾插进行,所以返回的时候要返回头结点的下一个结点。同时,因为存放数据小的链表和存放数据大的链表已经链接在一起了,所以只需要返回数据小的链表的首元结点,即可满足题目要求。
题目3:随机链表的复制
解题思路:
复制每一个结点(除最后一个空指针外),链接到每两个结点中间(或空指针和尾元结点之间)。具体如图一所示。
让每一个复制好的结点的random指向原链表被复制结点的random所指向的结点的next。具体如图二所示。
通过尾插的办法,让原链表和复制结点组成的链表分开,将复制结点组成的链表变成一个新链表,返回新链表的首元结点,题目解决。时间复杂度能够控制在O(n)以下。
图一
图二
代码:
typedef struct Node node;
struct Node* copyRandomList(struct Node* head) {
if(head ==NULL)
{
return head;
}
node* pcur=head;
node* newnode;
while(pcur)
{
node* newnode=(node*)malloc(sizeof(node));
newnode->val=pcur->val;
newnode->next=pcur->next;
pcur->next=newnode;
pcur=pcur->next->next;
}
pcur=head;
node* copy=head->next;
while(pcur)
{
if(pcur->random == NULL)
{
copy->random = NULL;
}
else
{
copy->random=pcur->random->next;
}
pcur=copy->next;
if(pcur)
{
copy=pcur->next;
}
}
if(head->next->next)
{
node* newhead,*newtail;
pcur=newhead=head->next;
newtail=pcur->next->next;
while(newtail->next)
{
pcur->next=newtail;
pcur=newtail;
newtail=newtail->next->next;
}
pcur->next=newtail;
return newhead;
}
else{
return (head->next);
}
}
代码讲解:
题设说明了,可能会出现空链表的情况。如果是空链表,那么就直接返回该链表。
开创新的结点,复制原结点的val值进去,插在原链表的两个结点中间。每次完成该操作以后,pcur往后走两个结点(一个结点是newnode、一个结点是原链表中的pcur所在结点的下一个结点)。
然后开始对random进行操作。当原链表某一被复制结点的random指向NULL,那么对应的复制节点的random也指向NULL。结束该操作以后,让pcur和copy同时往后走。
最后进行尾插操作,要分为只有一个结点的原链表、有两个及两个以上结点的原链表这两种情况。
对于只有一个结点的原链表,直接返回首元结点的下一个结点即可。
对于有两个及两个以上结点的原链表,通过尾插代码,完成操作,返回复制节点所组成的新链表的首元结点即可。