力扣hot100 - 合并两个有序链表21

cpp 复制代码
#include <iostream>
#include <vector>

// 定义链表节点结构体
struct ListNode {
    int val;
    ListNode *next;
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode *next) : val(x), next(next) {}
};

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        // 创建一个哨兵节点(dummy node),它的值不重要。
        // 使用哨兵节点可以避免处理新链表头节点为空的特殊情况。
        ListNode* dummy = new ListNode(-1);
        
        // tail 指针用于始终指向新链表的最后一个节点
        ListNode* tail = dummy;

        // 当两个链表都不为空时,比较它们头节点的值
        while (list1 != nullptr && list2 != nullptr) {
            if (list1->val <= list2->val) {
                // 如果 list1 的值较小,将 list1 接到 tail 后面
                tail->next = list1;
                // list1 指针后移
                list1 = list1->next;
            } else {
                // 如果 list2 的值较小,将 list2 接到 tail 后面
                tail->next = list2;
                // list2 指针后移
                list2 = list2->next;
            }
            // tail 指针后移,准备连接下一个节点
            tail = tail->next;
        }

        // 循环结束后,可能有一个链表还没有遍历完
        // 直接将剩余部分接在 tail 后面即可(因为剩下的部分本身就是有序的)
        if (list1 != nullptr) {
            tail->next = list1;
        } else if (list2 != nullptr) {
            tail->next = list2;
        }

        // 保存结果头节点(哨兵节点的下一个节点)
        ListNode* result = dummy->next;
        
        // 释放哨兵节点内存(虽然在算法题中通常不强制,但在实际工程中是好习惯)
        delete dummy;
        
        return result;
    }
};

// ==========================================
// 以下是辅助函数,用于本地测试代码运行结果
// ==========================================

// 辅助函数:根据数组创建链表
ListNode* createList(const std::vector<int>& vals) {
    if (vals.empty()) return nullptr;
    ListNode* head = new ListNode(vals[0]);
    ListNode* current = head;
    for (size_t i = 1; i < vals.size(); ++i) {
        current->next = new ListNode(vals[i]);
        current = current->next;
    }
    return head;
}

// 辅助函数:打印链表
void printList(ListNode* head) {
    ListNode* curr = head;
    std::cout << "[";
    while (curr != nullptr) {
        std::cout << curr->val;
        if (curr->next != nullptr) std::cout << ",";
        curr = curr->next;
    }
    std::cout << "]" << std::endl;
}

// 辅助函数:释放链表内存
void deleteList(ListNode* head) {
    while (head != nullptr) {
        ListNode* temp = head;
        head = head->next;
        delete temp;
    }
}

int main() {
    Solution solution;

    // 示例 1
    std::cout << "示例 1:" << std::endl;
    ListNode* l1 = createList({1, 2, 4});
    ListNode* l2 = createList({1, 3, 4});
    ListNode* merged1 = solution.mergeTwoLists(l1, l2);
    std::cout << "输出: ";
    printList(merged1);
    deleteList(merged1); // 清理内存

    // 示例 2
    std::cout << "\n示例 2:" << std::endl;
    ListNode* l3 = createList({});
    ListNode* l4 = createList({});
    ListNode* merged2 = solution.mergeTwoLists(l3, l4);
    std::cout << "输出: ";
    printList(merged2);
    deleteList(merged2);

    // 示例 3
    std::cout << "\n示例 3:" << std::endl;
    ListNode* l5 = createList({});
    ListNode* l6 = createList({0});
    ListNode* merged3 = solution.mergeTwoLists(l5, l6);
    std::cout << "输出: ";
    printList(merged3);
    deleteList(merged3);

    return 0;
}

代码逻辑简述:

  1. 哨兵节点 (dummy):我们创建了一个虚拟头节点。这使得我们无需编写额外的逻辑来判断"新链表的头是来自 l1 还是 l2",也无需在循环中判断"结果链表是否为空"。

  2. 双指针比较 :只要两个链表都不为空,就比较当前的头节点值。较小的那个节点被连接到 tail(结果链表的尾部),然后该链表的指针后移。

  3. 处理剩余部分 :当循环结束时,意味着其中一个链表已经空了。因为原链表是有序的,我们只需要直接把另一个非空链表的剩余部分直接链到 tail->next 即可,无需继续遍历。

复杂度分析:

  • 时间复杂度:O(n + m),其中 n 和 m 分别是两个链表的长度。我们需要遍历两个链表的每一个节点一次。

  • 空间复杂度:O(1)。我们只是调整了现有节点的指针,除了几个辅助指针外,没有分配新的节点空间。

相关推荐
墨染点香1 小时前
LeetCode 刷题【168. Excel 表列名称】
算法·leetcode·职场和发展
hans汉斯1 小时前
基于改进YOLOv11n的无人机红外目标检测算法
大数据·数据库·人工智能·算法·yolo·目标检测·无人机
Swift社区1 小时前
LeetCode 431 - 将 N 叉树编码成二叉树
算法·leetcode·职场和发展
子豪-中国机器人2 小时前
1030-csp 2019 入门级第一轮
算法
关注我立刻回关2 小时前
洛谷平台
算法
Cx330❀2 小时前
C++ map 全面解析:从基础用法到实战技巧
开发语言·c++·算法
CS_浮鱼3 小时前
【Linux】线程
linux·c++·算法
AndrewHZ4 小时前
【图像处理基石】如何入门图像配准算法?
图像处理·opencv·算法·计算机视觉·cv·图像配准·特征描述子
BanyeBirth4 小时前
C++窗口问题
开发语言·c++·算法