刷了leetcode 高级题集的链表部分,emmm都不会QWQ。
按照网上题解写了一遍,记录一下。
前两道排序的题,排序部分很简洁也很模板化。题目中建立dummy节点的操作也值得记录。第三道题是理解链表的好题目。
总之三道题都很值得去做并记忆。ヾ(◍°∇°◍)ノ゙
23. 合并K个元素的有序链表
题目
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
思路
单个链表已经有序,要做的是把它们合并。可以用归并排序的思想。
共有k个链表,相邻的两个链表合并,第一次操作剩余k/2,第二次操作剩余k/4,……。一共进行了log(k)次。
每次操作需要遍历所有元素值(我觉得这是不是可以根据单个有序的性质剪纸?),设每个链表长n,总元素个数是N=nk。
所以复杂度是
O
(
N
l
o
g
k
)
O(Nlogk)
O(Nlogk)。
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* merge(ListNode* l1,ListNode* l2)
{
if(!l1) return l2;
if(!l2) return l1;
ListNode* res=new ListNode(0);
ListNode* head=res;
while(l1&&l2)
{
//cout<<l1->val<<' '<<l2->val<<endl;
if(l1->val<=l2->val)
{
head->next=l1;
l1=l1->next;
}
else
{
head->next=l2;
l2=l2->next;
}
head=head->next;
}
if(l1)
head->next=l1;
if(l2)
head->next=l2;
cout<<res->next->val<<endl;
return res->next;
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
if(lists.empty())
return NULL;
while(lists.size()>1)
{
vector<ListNode*> tmp;
for(int i=1;i<lists.size();i+=2)
{
ListNode *p=merge(lists[i-1],lists[i]);
tmp.push_back(p);
}
if(lists.size()%2==1)
tmp.push_back(lists.back());
lists=tmp;
}
return lists.back();
}
};
147. 链表排序
题目
Sort a linked list in O(n log n) time using constant space complexity.
Input: 4->2->1->3
Output: 1->2->3->4
思路
要求O(nlogn)的复杂度和常数空间。也是使用归并排序。
排序的部分和上一道题很相似,应该是个模板的写法。
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
if(!head||!head->next)
return head;
ListNode *pre=head;
ListNode *slow=head;
ListNode *fast=head;
while(fast&&fast->next)
{
pre=slow;
slow=slow->next;
fast=fast->next->next;
}
pre->next=NULL;
return merge(sortList(head),sortList(slow));
}
ListNode* merge(ListNode* l1,ListNode *l2)
{
ListNode *dummy=new ListNode(0);
ListNode *cur=dummy;
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;
if(l2)
cur->next=l2;
return dummy->next;
}
};
105. 复制带随机指针的链表
题目
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.
Return a deep copy of the list.
思路
要求对链表深拷贝,要建立新的和它自己一样的节点,并包含原链表的随机映射关系。
先遍历链表,按其next顺序依次建新节点。其难点是,如何把随机指针指到新链表上,因为这个随机是乱序的,指的是原链表节点,因此要建立原链表节点和新链表节点的map,把原链表指向原链表节点的随机指针,在新链表中,指到新链表的对应节点上。
代码
/**
* Definition for singly-linked list with a random pointer.
* struct RandomListNode {
* int label;
* RandomListNode *next, *random;
* RandomListNode(int x) : label(x), next(NULL), random(NULL) {}
* };
*/
class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
if(!head)
return NULL;
map<RandomListNode*,RandomListNode*> m;
RandomListNode *res=new RandomListNode(head->label);
RandomListNode *node=res;
RandomListNode *cur=head->next;
m[head]=res;
while(cur)
{
RandomListNode *tmp=new RandomListNode(cur->label);
node->next=tmp;
m[cur]=tmp;
cur=cur->next;
node=node->next;
}
node=res;
cur=head;
while(node)
{
node->random=m[cur->random];
node=node->next;
cur=cur->next;
}
return res;
}
};