【被OJ毒打的第七天】LeetCode_简单_21.合并两个有序链表
题干:
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的
提示:
输入和输出的链表元素皆为从小到大排列!
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
输入:
2->3->4, 1->2->5
输出:
1->2->2->3->4->5
1.我的做法
执行用时:8~16ms,8.9MB
思想:在两个链表不为空时,持续遍历,遍历过程中比较当前位置两链表元素的大小,将小的一个添加到结果链表上,并让此链表和结果链表都前进一位
实现:首先考虑传入空链表的特殊情况(其实也不知道他到底有没有这个边缘用例);然后比较输入两链表头节点值的大小,用较小的那个值初始化 res;接着,需要拷贝一个链表 p 作为操作结果链表的指针(否则返回的 res 就只有最后一个节点);然后先对头结点值较小的链表做循环,循环结束后再对另一个链表做循环防止还有一些节点未被纳入 res
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if (l1 == NULL) {
return l2;
}
if (l2 == NULL) {
return l1;
}
ListNode* fir;
ListNode* sec;
if (l1->val <= l2->val) {
fir = l1;
sec = l2;
} else {
fir = l2;
sec = l1;
}
ListNode* res = new ListNode(fir->val);
fir = fir->next;
ListNode* p = res;
while (fir != NULL) {
if (sec != NULL && sec->val <= fir->val) {
p->next = new ListNode(sec->val);
p = p->next;
sec = sec->next;
} else {
p->next = new ListNode(fir->val);
p = p->next;
fir = fir->next;
}
}
while (sec != NULL) {
p->next = new ListNode(sec->val);
p = p->next;
sec = sec->next;
}
return res;
}
疑惑:由于原题目相当不清晰,我这段代码是带了一点之前的偏离思路的(分 fir 和 sec 实际上是不需要的);但是我重新修改过之后,执行时间反而变长了(12~28ms)...就很郁闷,我把改过的代码也贴在下面,个人猜测可能是由于:头节点值较小的链表中的值整体程度上也容易比另一个链表要小,所以先对其循环从数据上讲节省了时间(?)
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if (l1 == NULL) {
return l2;
}
if (l2 == NULL) {
return l1;
}
ListNode* res;
if (l1->val <= l2->val) {
res = new ListNode(l1->val);
l1 = l1->next;
} else {
res = new ListNode(l2->val);
l2 = l2->next;
}
ListNode* p = res;
while (l1 != NULL) {
if (l2 != NULL && l2->val <= l1->val) {
p->next = new ListNode(l2->val);
p = p->next;
l2 = l2->next;
} else {
p->next = new ListNode(l1->val);
p = p->next;
l1 = l1->next;
}
}
while (l2 != NULL) {
p->next = new ListNode(l2->val);
p = p->next;
l2 = l2->next;
}
return res;
}
2.进阶做法
执行用时:8~20ms,9MB(其实也没有很快,但是思路很棒)
思想:将当前位置较小的那个值定下来,指针后移,将剩余的两个链表部分再次递归合并
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1 == NULL) {
return l2;
}
if(l2 == NULL) {
return l1;
}
if(l1->val <= l2->val) {
l1->next = mergeTwoLists(l1->next, l2);
return l1;
} else {
l2->next = mergeTwoLists(l1, l2->next);
return l2;
}
}
现在发现其实 Top 2~3 的代码真正执行的时间也差不离,只是有时候突然会 0ms,4ms这样(也不知道为啥)
所以也不要过分追求执行速度啦!从多个角度思考题目,寻找巧妙的思路和完整的题解吧~
那么接下来就开始中等难度的挑战吧!
Fighting!!!