【一天一道LeetCode】#21. Merge Two Sorted Lists

一天一道LeetCode系列

(一)题目

Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

(二)解题

这题是剑指offer上的老题了,剑指上面用的是递归,我写了个非递归的版本。

/**
 * 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* head = NULL;
        if(l1==NULL && l2==NULL) return head;
        ListNode* p = NULL;
        ListNode* p1 = l1;
        ListNode* p2 = l2;
        while(p1 != NULL || p2!=NULL)
        {
            if(p1 != NULL && p2 != NULL)
            {
                if(p1->val < p2->val)
                {
                    if(head == NULL) //记录头节点head
                    {
                        head = p1;
                        p = head;
                    }
                    else {p->next = p1;p=p->next;}
                    p1=p1->next;

                }
                else
                {
                    if(head == NULL) 
                    {
                        head = p2;
                        p = head;
                    }
                    else {p->next = p2;p=p->next;}
                    p2=p2->next;
                }
            }
            if(p1 == NULL && p2 != NULL)
            {
                if(head == NULL) 
                {
                    head = p2;
                    p = head;
                }
                else {p->next = p2;p=p->next;}
                p2=p2->next;
            }
            if(p1 != NULL && p2 == NULL)
            {
                if(head == NULL) 
                {
                    head = p1;
                    p = head;
                }
                else {p->next = p1;p=p->next;}
                p1=p1->next;
            }
        }
        return head;
    }
};

递归版本:

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1 == NULL) return l2;
        if(l2 == NULL) return l1;
        ListNode* head;
        if(l1->val < l2->val)
        {
            head = l1;
            head->next = mergeTwoLists(l1->next , l2);
        }
        else
        {
            head = l2;
            head->next = mergeTwoLists(l1 , l2->next);
        }
        return head;
    }
};
<think> 首先,用户要求我逐行分析给定Python代码中的Solution类的merge函数并解释其作用。代码来自引用,特别是引用[2]和引用[4],因为它们涉及题解代码。 在引用中: - 引用[2]是关于LeetCode 021. Merge Two Sorted Lists递归解法。 - 引用[4]是关于LeetCode 23. Merge k Sorted Lists的解法。 用户指定了“Solution类的merge函数”,但在我看到的引用中,函数名是mergeTwoLists(在引用[2]中)和merge2Lists(在引用[4]中)。可能是个误称,我应该参考具体的代码。 用户说“merge函数”,但在引用中没有直接叫“merge”的函数。我需要澄清: - 在引用[2]中,函数是mergeTwoLists。 - 在引用[4]中,函数是merge2Lists。 用户提到“Solution类的merge函数”,所以很可能指的是这些合并函数。我应该基于给定的引用进行分析。 用户指令是:“我想逐行分析给定Python代码中Solution类的merge函数并解释其作用” 并且引用提供了代码片段: - 从引用[2]:递归解法 - 从引用[4]:迭代解法 我应该选择一个来分析,或者用户指定了哪个?用户没有指定具体引用,所以我可以选择基于上下文。或许用户指的是引用[4]中的merge2Lists函数,因为它是合并两个列表的函数。 为了安全起见,我应该参考mergeTwoLists函数,因为它更常见。 现在,系统级指令: - 所有行内数学表达式使用$...$。 - 独立公式使用$$...$$。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 引用的段落末尾添加引用标识,如[^1]。 用户可见层指令: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 回答结构: 1. 解释函数的作用:合并两个有序链表。 2. 逐行分析代码。 3. 最后生成相关问题。 选择哪个函数?引用[2]是递归解法,引用[4]是迭代解法。我可以先分析引用[4]中的merge2Lists函数,因为它更直接。 代码从引用[4]: ```python def merge2Lists(self, l1, l2): dummy = ListNode(0) p = dummy while l1 != None and l2 != None: if l1.val < l2.val: p.next = l1 l1 = l1.next else: p.next = l2 l2 = l2.next p = p.next if l1 != None: p.next = l1 elif l2 != None: p.next = l2 return dummy.next ``` 这是一个迭代方法合并两个有序链表。 逐行分析: - `def merge2Lists(self, l1, l2):`: 定义了一个方法merge2Lists,接收两个参数l1和l2,代表两个链表的头节点。 - `dummy = ListNode(0)`: 创建一个哑节点,用于简化链表操作。 - `p = dummy`: 设置一个指针p指向哑节点。 - `while l1 != None and l2 != None:`: 循环,直到l1或l2任一为空。 - `if l1.val < l2.val:`: 如果l1的值小于l2的值。 - `p.next = l1`: 将p的next指向l1。 - `l1 = l1.next`: 移动l1到下一个节点。 - `else:`: 否则。 - `p.next = l2`: 将p的next指向l2。 - `l2 = l2.next`: 移动l2到下一个节点。 - `p = p.next`: 移动p到下一个节点。 - `if l1 != None:`: 如果l1还有剩余节点。 - `p.next = l1`: 将剩余节点连接到p的next。 - `elif l2 != None:`: 如果l2还有剩余节点。 - `p.next = l2`: 将剩余节点连接到p的next。 - `return dummy.next`: 返回合并后链表的头节点(因为dummy.next指向实际头节点)。 这是一个标准的合并两个有序链表的算法,时间复杂度为$O(n+m)$,其中n和m是两个链表的长度。 使用中文解释: - 函数作用:合并两个有序链表,返回一个新的有序链表。 - 逐行解释。 生成相关问题: - 类似于示例的结构。 最后,添加引用标识:[^2] for the code from citation [2], but I&#39;m using [4]. 用户引用中,[^1]是索引,[^2]是递归解法,[^3]和[^4]是其他代码。我应该引用相应的部分。 在回答中,我需要自然地添加引用标识。 结构回答: 1. 介绍函数作用。 2. 逐行分析代码。 3. 总结。 4. 生成相关问题。 </think> ### 逐行分析Python代码中的`merge2Lists`函数 在LeetCode问题中,`Solution`类的`merge2Lists`函数用于合并两个有序链表(singly-linked list),生成一个新的有序链表。这是一个关键操作,在合并多个有序链表(如LeetCode 23题)或其他排序算法中广泛应用。以下基于引用[4]提供的代码进行逐行分析。代码采用迭代方法实现,时间复杂度为$O(n + m)$,其中$n$和$m$是两个链表的长度,空间复杂度为$O(1)$(仅使用常数级额外空间)[^4]。 #### 代码逐行解释 ```python def merge2Lists(self, l1, l2): ``` - **行1**: 定义方法`merge2Lists`,属于`Solution`类。参数`l1`和`l2`分别表示两个有序链表的头节点。如果链表为空(`None`),则直接返回另一个链表。 ```python dummy = ListNode(0) ``` - **行2**: 创建一个哑节点(dummy node),值为0。哑节点简化了链表操作,避免了处理头节点为空的边界情况。哑节点的`next`指针将指向合并后链表的实际头节点。 ```python p = dummy ``` - **行3**: 初始化指针`p`,指向哑节点。`p`用于遍历和构建新链表。 ```python while l1 != None and l2 != None: ``` - **行4**: 循环条件:当`l1`和`l2`均非空时执行循环。目标是逐一比较两个链表的当前节点值,并将较小值添加到新链表中。循环确保只处理有效节点,避免空指针错误。 ```python if l1.val < l2.val: ``` - **行5**: 判断条件:如果`l1`的当前节点值小于`l2`的当前节点值。这确保了新链表保持升序排列。 ```python p.next = l1 ``` - **行6**: 将`p.next`指向`l1`的当前节点。这相当于将较小的节点(来自`l1`)链接到新链表尾部。 ```python l1 = l1.next ``` - **行7**: 移动`l1`指针到下一个节点。因为`l1`的当前节点已被处理,需要推进到剩余部分。 ```python else: ``` - **行8**: 如果`l1.val >= l2.val`,则处理`l2`的节点(`else`分支覆盖相等或更大的情况)。 ```python p.next = l2 ``` - **行9**: 将`p.next`指向`l2`的当前节点(较小或相等的值)。 ```python l2 = l2.next ``` - **行10**: 移动`l2`指针到下一个节点。 ```python p = p.next ``` - **行11**: 移动`p`指针到新链表的尾部。这确保了`p`始终指向当前已构建链表的最后一个节点,以便继续添加新节点。 ```python if l1 != None: ``` - **行12**: 循环结束后,检查`l1`是否剩余节点(即`l2`已为空,但`l1`还有节点)。此时,剩余节点已有序,可以直接链接。 ```python p.next = l1 ``` - **行13**: 将剩余`l1`的整个子链表连接到`p.next`,无需再遍历,因为剩余部分已有序。 ```python elif l2 != None: ``` - **行14**: 如果`l2`剩余节点(即`l1`已空),类似处理。 ```python p.next = l2 ``` - **行15**: 将剩余`l2`子链表链接到新链表尾部。 ```python return dummy.next ``` - **行16**: 返回`dummy.next`,即合并后链表的实际头节点。哑节点`dummy`本身不存储有效数据,其`next`指向第一个真实节点。 #### 函数作用总结 `merge2Lists`函数的作用是**合并两个有序链表为一个新的有序链表**。它通过迭代遍历两个链表,比较节点值,并将较小值依次链接到新链表中。如果任一链表为空,则直接返回另一个链表。算法高效且稳健,常用于复杂排序问题(如合并K个有序列表)的基础操作[^4]。 ### 相关问题 1. **如何处理链表合并中的边界条件?** (需要考虑链表为空或长度不一致的情况。) 2. **迭代法与递归法合并链表的优缺点比较?** (引用[2]提供了递归解法,适合对比性能差异。) 3. **在合并多个有序链表时,如何优化时间复杂度?** (引用[4]的代码展示了如何用两两合并处理K个链表。) 4. **链表合并算法在实际应用中的场景有哪些?** (如数据库查询优化、大数据排序等。)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值