牛客网在线编程第5题—— 合并k个已排序的链表

这道题被爱学习的你看到了,很棒!那今天就花十五分钟的时间,一起来看下链表中的节点每k个一组翻转。来说下解题思路:

将一个数组每次划分成等长的两部分,对两部分进行排序即是子问题。对子问题继续划分,直到子问题只有1个元素。还原的时候,将每个子问题和它相邻的另一个子问题利用上述双指针的方式,1个与1个合并成2个,2个与2个合并成4个,因为这每个单独的子问题合并好的都是有序的,直到合并成原本长度的数组。

对于这k个链表,就相当于上述合并阶段的k个子问题,需要划分为链表数量更少的子问题,直到每一组合并时是两两合并,然后继续往上合并,这个过程基于递归:

  • 终止条件: 划分的时候直到左右区间相等或左边大于右边。
  • 返回值: 每级返回已经合并好的子问题链表。
  • 本级任务: 对半划分,将划分后的子问题合并成新的链表。

具体做法:

  • step 1:从链表数组的首和尾开始,每次划分从中间开始划分,划分成两半,得到左边n/2个链表和右边n/2个链表。
  • step 2:继续不断递归划分,直到每部分链表数为1个节点。
  • step 3:将划分好的相邻两部分链表,按照两个有序链表合并的方式合并,合并好的两部分继续往上合并,直到最终合并成一个链表。
class Solution {
  public:
    ListNode* Merge2(ListNode* pHead1, ListNode* pHead2) {
        if (pHead1 == NULL)
            return pHead2;
        if (pHead2 == NULL)
            return pHead1;
        ListNode* head = new ListNode(0); //加一个表头
        ListNode* cur = head;
        while (pHead1 && pHead2) { //两个链表都不为空时,取较小值的节点
            if (pHead1->val <= pHead2->val) {
                cur->next = pHead1; //只移动取值的指针
                pHead1 = pHead1->next;
            } else {
                cur->next = pHead2; //只移动取值的指针
                pHead2 = pHead2->next;
            }
            //指针后移
            cur = cur->next;
        }
        if (pHead1)
            cur->next = pHead1; //把剩下的接到后面
        else
            cur->next = pHead2;
        return head->next; //返回值去掉表头
    }
    //划分合并区间函数
    ListNode* divideMerge(vector<ListNode*>& lists, int left, int right) {
        if (left > right)
            return NULL;
        else if (left == right)
            return lists[left];
        int mid = (left + right) /
                  2; //从中间分成两段,再将合并好的两段合并
        return Merge2(divideMerge(lists, left, mid), divideMerge(lists, mid + 1,
                      right));
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        return divideMerge(lists, 0, lists.size() - 1); //k个链表归并排序
    }
};

 

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值