LeetCode(C++)刷题计划:21-合并两个有序链表

21-合并两个有序链表

@Author:CSU张扬
@Email:csuzhangyang@gmail.com or csuzhangyang@qq.com

Category Difficulty Pass rate Tags Companies
algorithms Easy 57.92% linked-list amazon / apple / linkedin / microsoft

1. 题目

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/

2. 解法

2.1 解法一:归并排序

  1. 创建一个新的链表 h ,用于存储合并后的链表。
  2. 遍历两个链表。比较两者当前的 val 大小,小的则加入到 h 中,并向后移,另外一个链表不用移动。直至某一个链表遍历到尾部,结束。
  3. 此时肯定有一个链表没有遍历到尾部,将这个链表剩余的元素依次加入到 h 后面即可。

执行用时: 8 ms, 在所有 cpp 提交中击败了96.15%的用户
内存消耗: 9.1 MB, 在所有 cpp 提交中击败了73.70%的用户

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* h = new ListNode(0);
        ListNode* head = h;
        while(l1 && l2) {
            if (l1->val < l2->val) {
                h->next = new ListNode(l1->val);
                h = h->next;
                l1 = l1->next;
            } else {
                h->next = new ListNode(l2->val);
                h = h->next;
                l2 = l2->next;
            }
        }
        if (l1) {
            while(l1) {
                h->next = new ListNode(l1->val);
                h = h->next;
                l1 = l1->next;
            }
        } else if (l2) {
            while(l2) {
                h->next = new ListNode(l2->val);
                h = h->next;
                l2 = l2->next;
            }
        }
        ListNode* ptrDelete = head;
        head = head->next;
        delete ptrDelete;
        return head;
    }
};

2.2 解法二:递归(两种)

2.2.1 简单递归

参考zxyperfect

  1. 递归思路:
    我们每次从两个链表的头结点选出一个较小的放在结果中,并在原链表中删除该结点,然后继续比较两个链表。直至一个链表为空。
  2. 递归结束条件:
    当某个链表为空时,递归结束,但我们返回的是另一个链表。因为另一个链表剩下的肯定是值最大的那部分。例如:if(l1 == nullptr) { return l2; }

执行用时: 12 ms, 在所有 cpp 提交中击败了69.38%的用户
内存消耗: 9 MB, 在所有 cpp 提交中击败了74.60%的用户

class Solution {
public:
    ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
        if(l1 == nullptr){
            return l2;
        }
        if(l2 == nullptr){
            return l1;
        }
        if(l1->val <= l2->val){
            l1->next = mergeTwoLists(l1->next, l2);
            return l1;
        }
        else{
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};

2.2.2 利用swap函数递归

参考 StefanPochmann

swap函数介绍:
swap(a, b) :交换a和b。在此结构体中的意思就是 a->nextb->next 交换,a->valb->val 也交换。

  1. 首先注意,我们的合并后的链表是 a 头结点所指向的链表,也就是 a 所走过的位置, 都被按顺序加了进来。
  2. 总的思想就是:若 a->val > b->val ,就 swap(a, b) ,把 a 放到小的那个节点。
    反之,a 继续向所在节点后面移动,继续比较,a 会始终保持在较小的那个节点上。
  3. a 所在链表到达尾部时(a = nullptr),说明另外一个链表剩余的都是最大的几个值,我们这时仍需要 swap(a, b) ,将 a 放到另一个链表剩余的值上。
  4. 后续我会画个图例出来。

执行用时 :8 ms, 在所有 cpp 提交中击败了95.91%的用户
内存消耗 :8.7 MB, 在所有 cpp 提交中击败了97.11%的用户

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* a, ListNode* b) {
        if (!a || b && a->val > b->val) swap(a, b);
        if (a) a->next = mergeTwoLists(a->next, b);
        return a;
    }
};
原文地址:https://www.cnblogs.com/MagicConch/p/12179149.html