牛客刷题日记【合并k个已排序的链表|判断链表中是否有环|链表中环的入口结点]

BM7 链表中环的入口结点

给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。

数据范围: n≤10000n≤10000,1<=结点值<=100001<=结点值<=10000

要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)

思考:

根据阅读题目和样例可知,链表正常情况下按照递增序列排序

因此仅需记录pre和cur节点,当出现cur<=pre时,即为环入口,返回cur

代码:

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        int pre = -1, cur = pHead->val;

        while (pHead->next != nullptr) {
            pre = cur;
            pHead = pHead->next;
            cur = pHead->val;

            if (cur <= pre) return pHead;
        }

        return nullptr;
    }
};


BM6 判断链表中是否有环

判断给定的链表中是否有环。如果有环则返回true,否则返回false。

数据范围:链表长度 0≤n≤100000≤n≤10000,链表中任意节点的值满足 ∣val∣<=100000∣val∣<=100000

要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)

输入分为两部分,第一部分为链表,第二部分代表是否有环,然后将组成的head头结点传入到函数里面。-1代表无环,其它的数字代表有环,这些参数解释仅仅是为了方便读者自测调试。实际在编程时读入的是链表的头节点。

思考:

对有环链表进行遍历,会陷入无限循环,因此记录链表长度,当达到最大值的时候,一定存在环

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        int len = 0;

        // bool flag = false;

        while (head != nullptr)  {
            head = head->next;
            len++;
            if (len > 10000) return true;
        }

        return false;
    }
};

BM5 合并k个已排序的链表 ※※※

合并 k 个升序的链表并将结果作为一个升序的链表返回其头节点。

数据范围:节点总数 0≤n≤50000≤n≤5000,每个节点的val满足 ∣val∣<=1000∣val∣<=1000

要求:时间复杂度 O(nlogn)

思考:

建立一个优先队列,把所有链表的头节点放入队列中。

对优先队列进行遍历,将最小的节点以尾插法的形式插入新链表中,维持升序。

失去最小元素的链表将后续节点加入优先队列中,反复筛选最小节点。

比较器

比较规则说明:

  • return a->val > b->val 表示:
    • a->val 大于 b->val 时返回 true
    • 这会导致容器将较小的值放在前面(升序排列)
    • 在优先队列中,这会创建一个小顶堆(最小元素在顶部)
  • 如果改为 return a->val < b->val
    • 将创建一个大顶堆(最大元素在顶部)

比较器的返回值有两个应用场景,分别是:

1)是否交换两个元素的位置,True并表示不交换

2)表示优先级,True表示前一个元素的优先级更低

struct cmp {
    bool operator()(ListNode* a, ListNode* b) {
        return a->val > b-> val;
    }
};

代码

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 *	ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
#include <bits/types/struct_tm.h>
#include <queue>
#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param lists ListNode类vector 
     * @return ListNode类
     */

    struct cmp {
        bool operator()(ListNode* a, ListNode* b) {
            return a->val > b-> val;
        }
    };
    
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        // write code here

        std::priority_queue<ListNode*, std::vector<ListNode *>, cmp> pq;

        for(int i = 0;i < lists.size();i++)  if (lists[i] != nullptr)    pq.push(lists[i]);
        
        ListNode* res = new ListNode(0);
        ListNode* cur = res;

        while (!pq.empty()) {
            ListNode* tmp = pq.top();
            pq.pop();

            // 尾插法
            cur->next = tmp;
            cur = cur->next;

            if (tmp->next)  pq.push(tmp->next);
        }

        return res->next;
    }
};


 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值