合并k个已排序的链表
题目来源:Leetcode
1、问题描述
给定一个链表数组,每个链表都已经按升序排列。
请将所有链表合并到一个升序链表中,返回合并后的链表。
示例:
2、思路解析
思路一就是归并思想:
首先将前两个链表合并得到一个新的链表,遍历链表数组每次将数组和新得到一个链表合并得到一个新的链表具体步骤如下:
- step1首先将链表数组的前两个链表合并为一个有序链表
- step2遍历数组将新得到的链表和链表数组中下一个链表合并为一个新链表
- step3重复步骤3直到遍历完数组
合并过程如下:
思路二优先级队列:
思路就是将数组中链表的按头节点数值大小插入到小堆中没插入一个链表,小堆每一个节点都是链表的头节点。小堆就按照链表头节点的数组大小调整数组,保证还是维持小堆的结构,当把链表数组链表遍历完是,就把链表全插入到小堆了。接下来是将小堆链表按顺序插入到新链表中了。遍历优先级队列取节点,因为优先级队列是按照链表头节点数值大小排序,所以每次只需将堆顶的链表拿出来将头节点插入到新链表中,再把取下来链表的头节点的下一个节点地址插入到堆中,堆会再次按照头节点得到数组大小调整堆结构。
合并过程如下:
假设数组就这3个链表为了后续的方便给每个链表都起了一个名字
接着将链表插入到优先级队列中
插入方式是按照链表头节点数值大小插入的
接下来是遍历优先级队列按照顺序构建有序链表
后续按照上边步骤一次进行,直到堆中再无链表
3、代码实现
ListNode *_mergeKLists(ListNode *phead1,ListNode*phead2){
//增加头节点
ListNode*phead=new ListNode(-1);
ListNode*cur=phead;
while(phead1&&phead2){
if(phead1->val<=phead2->val){
cur->next=new ListNode(phead1->val);
phead1=phead1->next;
cur=cur->next;
}else{
cur->next=new ListNode(phead2->val);
phead2=phead2->next;
cur=cur->next;
}
}
//哪个链表先空就链接另一个
cur->next=phead1?phead1:phead2;
return phead->next;
}
//两两连接
//归并解决问题线性解决来浪费时间
//
ListNode*marge(vector<ListNode*>lists,int row,int col){
//先分在并
//返回条件
if(row==col){
return lists[row];
}
if(row>col){
return NULL;
}
int mid=(row+col)/2;
//将lists分分割成一个一个的链表
ListNode*li=marge(lists,row,mid);
ListNode*l2=marge(lists,mid+1,col);
//归并
return _mergeKLists(li,l2);
}
ListNode *mergeKLists(vector<ListNode *> &lists) {
if(lists.empty()){
return NULL;
}
if(lists.size()==1){
return lists[0];
}
return marge(lists,0,lists.size()-1);
}
这种方法相对简单但是链表合并次数太多,对于有时间要求的地方不一定能过
class Solution {
public:
//优先级队列解决
//建造小堆
struct cmp{
bool operator()(ListNode*l1,ListNode*l2){
return l1->val>l2->val;
}
};
ListNode *mergeKLists(vector<ListNode *> &lists) {
if(lists.empty()){
return NULL;
}
if(lists.size()==1&&lists[0]==NULL){
return NULL;
}
priority_queue<ListNode*,vector<ListNode*>,cmp> q;
//先入队
//排序是按照每个链表的头节点的值排序的
for(int i=0;i<lists.size();i++){
if(lists[i]){
q.push(lists[i]);
}
}
//入队时已经按照小队的顺序排序好了
//对顶就是全部链表头节点的最小的值了
//虚头节点
ListNode*phead=new ListNode(-1);
ListNode*cur=phead;
while(!q.empty()){
//取对顶元素的头节点
ListNode* top=q.top();
cur->next=top;
cur=cur->next;
q.pop();
//取堆顶链表的头节点头如果不为空又将其拆入队列,重新排序
if(top->next){
q.push(top->next);
}
}
return phead->next;
}
};
环形链表Ⅱ
题目来源:Leetcode
1、题目描述
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例:
2、思路解析;
将前边没有环的节点地址存储到数组中,然后判断数值中有没有节点地址,如果节点出现第一次在数组中找到这个节点地址就是环形链表的第一个节点
3、代码实现
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head==NULL){
return NULL;
}
unordered_set<ListNode*>s;
while(head){
//判断节点地址是不是再节点中存在存在就返回第一个存在的节点
if(s.find(head)!=s.end()){
return head;
}
s.insert(head);
head=head->next;
}
return NULL;
}
};