面试必刷算法TOP101之链表篇 TOP12

合并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;
    }
};
  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

自首的小偷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值