题目:对于两个有序链表,将它们合并成一个有序链表。
这种题目一看就是利用归并排序的思想,实现方式有递归和非递归两种方式。
方法1(非递归):
代码如下:
class Solution { public: ListNode* Merge(ListNode* pHead1, ListNode* pHead2) { if(pHead1 == nullptr) return pHead2; if(pHead2 == nullptr) return pHead1; ListNode *mHead = nullptr; ListNode *p1 = pHead1; ListNode *p2 = pHead2; ListNode *rs = nullptr; if(p1->val <= p2->val) { mHead = p1; p1 = p1->next; rs = pHead1; } else { mHead = p2; p2 = p2->next; rs = pHead2; } while(p1 != nullptr && p2 != nullptr) { if(p1->val <= p2->val) { mHead->next = p1; mHead = p1; p1= p1->next; } else { mHead->next = p2; mHead = p2; p2= p2->next; } } while(p1 != nullptr) { mHead->next = p1; p1 = p1->next; } while(p2 != nullptr) { mHead->next = p2; p2 = p2->next; } return rs; } };
(1)非递归的方式时间复杂度为O(n),空间复杂度为O(1)。
(2)尤其重要的一点是,在做这道题目时,一定要搞清楚最终返回的合并后的链表是一个新的链表还是可以是原来的链表(pHead1或者pHead2)。因为这两种情况思想是一致的,但对应的方法是不同的,前者需要重新建立一个链表,所需的空间复杂度为O(n),而后者只需在原链表上改动,时间复杂度为O(1)。(这段代码上我默认的是后者)
(3)如果L1为空返回L2,如果L2为空返回L1.这个特判情况需要注意。
(4)在一开始需要判断一次,用来确认头结点的位置;mHead仅仅是合并过程中的辅助变量。最终返回结果是一开始确立的头结点。
方法2(递归):
代码如下:
class Solution { public: ListNode* Merge(ListNode* pHead1, ListNode* pHead2) { if(pHead1 == nullptr) return pHead2; if(pHead2 == nullptr) return pHead1; ListNode * newHead = nullptr; if(pHead1->val < pHead2->val) { newHead = pHead1; newHead->next = Merge(pHead1->next,pHead2); } else { newHead = pHead2; newHead->next = Merge(pHead1,pHead2->next); } return newHead; } };
递归法的时间复杂度为O(n),空间复杂度为O(n),相比非递归效率要低一些。但是代码更易理解。且递归法返回的实际上是一个新的链表,即之前所说的第一种情况(遇到这种题目时,必须要搞清楚属于哪种情况)。