当前位置: 首页 > news >正文

Leetcode 21-25题

合并两个有序链表

将两个升序链表合并为一个新的升序链表。

用两个指针指向两个链表的表头,然后每次比较一下哪个值小,将较小的节点接到答案后面即可。

ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
    auto dummy = new ListNode(), p = dummy;
    auto l1 = list1, l2 = list2;
    while(l1 && l2) {   // 当l1和l2都不为空才进入循环
        if(l1->val <= l2->val) {
            p->next = l1;   // 将l1节点接到答案尾部
            p = p->next;    // 将答案和l1后移
            l1 = l1->next;
        }else {
            p->next = l2;
            p = p->next;
            l2 = l2->next;
        }
    }
    if(l1)  p->next = l1;
    if(l2)  p->next = l2;
    return dummy->next;
}

括号生成

n n n对括号,生成所有可能并且有效的括号组合。

有效的就是要满足任意前缀中左括号的数量一定大于等于右括号的数量。

然后做DFS,每次递归时都要保证左括号数量大于等于右括号数量。

也就是说,只有左括号数量大于右括号数量时,才可以放右括号。(前提是还有右括号可以放)

vector<string> ans;

void dfs(int n, int l, int r, string path) {
    if(l == n && r == n) {          // 左右括号都放满了则输出
        ans.push_back(path);
        return ;
    }
    if(l != n)  dfs(n, l + 1, r, path + "(");       // 若有左括号就可以直接放
    if(r != n && l > r) dfs(n, l, r + 1, path + ")");   // 若有右括号且前缀中左括号数量严格大于右括号数量则可以放
}

vector<string> generateParenthesis(int n) {
    dfs(n, 0, 0, "");
    return ans;
}

合并K个升序链表

给定一个链表数组,每个链表均为升序排列,将所有链表合并到一个升序链表中。

本质上和合并两个有序链表相似,即每次找最小的节点并接到答案后面。但是这样每次找会有 O ( k ) O(k) O(k)的比较次数。

因此可以采用堆优化来查找最小值,即每次把每个链表都存一个节点到堆中,取最小值接到答案后面,是 O ( 1 ) O(1) O(1)的比较次数。

优先队列默认是大根堆,要重载小于号才能变成小根堆,如priority_queue<int, vector< int>, greater< int>> q;

若要重载其他数据结构的小于比较,需要仿函数来重载。

struct cmp {
    bool operator() (ListNode* a, ListNode* b) {    // 仿函数
        return a->val > b->val;                     // 重载为大于
    }
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
    auto dummy = new ListNode(), p = dummy;
    priority_queue<ListNode*, vector<ListNode*>, cmp> heap;

    for(auto list : lists)  
        if(list)    heap.push(list);    // 样例2中有空链表
    while(!heap.empty()) {
        auto list = heap.top();         // 队头是最小的节点
        heap.pop();

        p->next = list;
        p = p->next;
        if(list->next)  heap.push(list->next);
    }
    return dummy->next;
}

两两交换链表中的节点

两两交换链表中相邻的节点,并返回交换后链表的头节点。

所有链表题,只要涉及到头节点的判断问题,都可以加一个虚拟头节点

head -> 1 -> 2 -> 3 -> 4 -> tail
head -> 2 -> 1 -> 3 -> 4 -> tail

要实现上述链表的两两交换,比如要交换1和2节点,需要将head指向2,将1指向3,将2指向1,实现这三步即可。

i -> j -> k -> l
交换j和k
i->next = k
j->next = k->next
k->next = j
ListNode* swapPairs(ListNode* head) {
    auto dummy = new ListNode(-1, head), p = dummy;
    while(p->next && p->next->next) {
        // p -> a -> b
        auto a = p->next, b = a->next;
        p->next = b;
        a->next = b->next;
        b->next = a;
        if(p->next->next)   p = p->next->next;
    }
    return dummy->next;
}

K个一组翻转链表

将链表每 k k k个节点一组进行翻转,返回修改后的链表。如果节点总数不是 k k k的整数倍,最后剩余的节点保持原有顺序。

head -> 1 -> 2 -> 3 -> 4 -> 5 -> tail
head -> 4 -> 3 -> 2 -> 1 -> 5 -> tail
head    1 <- 2 <- 3 <- 4    5 -> tail
		a    b
			 a    b
			 	  a    b

我们采取这样的策略,先改变内部的方向,内部都更改完之后,再更改两边的指向关系,如下代码和示意图:

ListNode* reverseKGroup(ListNode* head, int k) {
    auto dummy = new ListNode(-1, head);
    for (auto p = dummy;;) {
        auto q = p;
        for (int i = 0; i < k && q; i ++ ) q = q->next;
        if (!q) break;      // 以上为判断后面是否还有k个元素

        // head -> 1 -> 2 -> 3 -> 4 -> 5 -> tail
        //    p    a    b
        //    p         a    b
        //    p              a    b
        auto a = p->next, b = a->next;
        for (int i = 0; i < k - 1; i ++ ) {
            // a -> b -> c
            auto c = b->next;
            // a <- b  c
            b->next = a;
            // 移动到下一轮更改的位置
            a = b, b = c;
        }
        // head    1 <- 2 <- 3 <- 4    5 -> tail
        //    p    c              a    b
        // head    4 -> 3 -> 2 -> 1    5 -> tail
        //    p    a              c    b
        auto c = p->next;
        p->next = a, c->next = b;
        // head -> 4 -> 3 -> 2 -> 1 -> 5 -> tail
        //                        p
        p = c;
    }
    return dummy->next;
}

相关文章:

  • 消息队列RabbitMQ-使用过程中面临的问题与解决思路
  • OpenCV-36 多边形逼近与凸包
  • 【网络安全】什么样的人适合学?该怎么学?
  • NoSQL 数据库管理工具,搭载强大支持:Redis、Memcached、SSDB、LevelDB、RocksDB,为您的数据存储提供无与伦比的灵活性与性能!
  • c#的反汇编对抗
  • 推荐彩虹知识付费商城免授权7.0源码
  • 第99讲:MHA高可用集群配置实战:邮件告警和Binlog服务器搭建详解
  • NineAi 新版AI系统网站源码 ChatGPT
  • 前端新手Vue3+Vite+Ts+Pinia+Sass项目指北系列文章 —— 第十二章 常用工具函数 (Utils配置)
  • C语言:生成校验码
  • javaSE和javaEE区别
  • HTML 字符实体参考清单
  • Java使用Redis实现消息队列
  • 【算法】约瑟夫环问题解析与实现
  • 【正点原子STM32连载】 第五十二章 串口IAP实验 摘自【正点原子】APM32E103最小系统板使用指南
  • Lag-Llama:第一个时间序列预测的开源基础模型介绍和性能测试
  • PTA | Wifi密码
  • 5G网络eMBB、uRLLC、mMTC
  • “分布式透明化”在杭州银行核心系统上线之思考
  • 前端判断对象为空
  • 辽宁辽阳市白塔区一饭店发生火灾,当地已启动应急响应机制
  • 中国海油总裁:低油价短期影响利润,但也催生资产并购机会
  • “乐购浦东”消费券明起发放,多个商家同期推出折扣促销活动
  • 买新房可申领学位,广州南沙出台购房入学政策
  • 河北:开展领导干部任性用权等形式主义官僚主义问题专项整治
  • 光明网评论员:手机“二次放号”,需要重新确认“你是你”