目录
一、题目描述
二、初次解答
1. 思路:首先,定义一个头指针指向额外申请的头节点空间(最后要free)。其次,定义一个临时指针temp指向新增的链表节点。最后,循环比较list1->val和list2->val的大小,哪个小就链接到temp指针后面,并且往后走。当list1和list2其中一个为空时,就将temp指向另一个指针地址并且跳出循环。
2. 代码:
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) { /* 健壮性考虑 */ if (list1 == NULL) return list2; if (list2 == NULL) return list1; /* 合并两个链表 */ struct ListNode* ret = (struct ListNode*)malloc(sizeof(struct ListNode));//新链表的头指针,指向头节点 struct ListNode* temp = ret; //辅助指针 while (1) { if (list1 == NULL) { temp->next = list2; break; } if (list2 == NULL) { temp->next = list1; break; } if (list1->val <= list2->val) { temp->next = list1; temp = temp->next; list1 = list1->next; } else { temp->next = list2; temp = temp->next; list2 = list2->next; } } /* 释放头节点 */ temp = ret; ret = ret->next; free(temp); return ret; }
3. 优点:①由于仅遍历一遍这两个单链表,时间复杂度仅为O(n+m);②由于引入了头节点,对于第一个节点的操作和后续节点的操作一致。
4. 缺点:引入了头节点,算法执行过程中占用了一定的额外空间且需要最后free头节点。
三、官方解法
官方解法有两个:①递归;②迭代(与上述解法类似,不再赘述)。由于递归需要额外的递归栈空间,并且时间复杂度也相差不大。因此,这里不考虑递归解法。
四、C++写法
/**
* Definition for singly-linked list.
* 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) {
//list1为空则返回list2
if (!list1)
return list2;
//list2为空则返回list1
if (!list2)
return list1;
//循环比较list1和list2的节点大小,小的插入新链表中
ListNode *ret = new ListNode;
ListNode *it = ret;
while (list1 || list2) {
if (!list2 || list1 && list1->val < list2->val) {
it->next = new ListNode(list1->val);
list1 = list1->next;
} else {
it->next = new ListNode(list2->val);
list2 = list2->next;
}
it = it->next;
}
//释放头结点,返回新链表
it = ret;
ret = ret->next;
delete it;
return ret;
}
};
五、总结
在新建单链表时,头结点的引入使得第一个结点和后续结点的操作一致,减少代码量。