剑指offer - 面试题25: 合并两个排序的链表 - C++

自己千辛万苦写出的循环:

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1 == nullptr) return pHead2;
        if(pHead2 == nullptr) return pHead1;
         
        ListNode * pHeadNew = new ListNode(0);
        ListNode * pNode = pHeadNew;
         
        ListNode * pNode1 = pHead1, * pNode2 = pHead2;
         
        if(pHead1->val <= pHead2->val) {
            pNode->val = pHead1->val;
            pNode1 = pHead1->next;
        } else {
            pNode->val = pHead2->val;
            pNode2 = pHead2->next;
        }
         
        while(pNode1 != nullptr && pNode2 != nullptr) {
            pNode->next = new ListNode(0);
            pNode = pNode->next;
            if(pNode1->val <= pNode2->val) {
                pNode->val = pNode1->val;
                pNode1 = pNode1->next;
            } else {
                pNode->val = pNode2->val;
                pNode2 = pNode2->next;
            }
        }
         
        ListNode * pRemain = nullptr;
        if(pNode1 != nullptr) {
            pRemain = pNode1;
        } else if(pNode2 != nullptr) {
            pRemain = pNode2;
        }
        if(pRemain != nullptr) {
            while(pRemain != nullptr) {
                pNode->next = new ListNode(0);
                pNode = pNode->next;
                pNode->val = pRemain->val;
                pRemain = pRemain->next;
            }
        }
        // pNode->next = nullptr;
        return pHeadNew;
    }
};

 

居然写了50+行,真是没sei了。

刚开始好几次没过,主要是因为struct新建节点不熟悉,用它的构造函数却不想有初始值,导致参数类型错误。再次提醒自己:c++中函数的参数及返回值的类型、顺序非常严格,一丝不苟。

编译通过以后又case通过率0%,原因是边界没处理好。刚开始写的是一个节点赋完值后,就new一个节点,再下一轮while循环,这样是不对的,因为不一定有下一个节点了。应该先检测有没有下一个节点再new。 所以改变new的位置后,发现第一个节点已经有了,就不用new了。但是再while循环中加if语句达不到目的,所以手动处理了第一个节点。以上就是我用循环写的全部过程,虽然代码量长,但也算逻辑清晰&无冗余。

 

然后参考了书上它说用递归!对啊!“这是典型的递归”!

于是自己又写递归,改进后的不改变原链表的答案如下:

// 递归解法
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
       if(pHead1 == nullptr) return pHead2;
       if(pHead2 == nullptr) return pHead1;
        
       ListNode* pHeadNew = new ListNode(0);
       if(pHead1->val <= pHead2->val) {
           pHeadNew->val = pHead1->val;
           pHeadNew->next = Merge(pHead1->next, pHead2);
       } else {
           pHeadNew->val = pHead2->val;
           pHeadNew->next = Merge(pHead1, pHead2->next);
       }
        return pHeadNew;
    }
};

这次代码简洁了不少。但是又看书上,发现它没有新建节点,但是改变了原链表,相当于把原链表中的指针擦除,按要求重新串起来了。我觉得呢,这种方法不一定就是好的,具体要看面试官的要求,有没有要求原链表保留,有没有要求不用额外的空间呢。所以,递归+不用额外空间的解法如下:

// 递归解法 不需要创建新节点,改变原链表指针即可
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
       if(pHead1 == nullptr) return pHead2;
       if(pHead2 == nullptr) return pHead1;
         
       ListNode * pHeadNew;
       
       if(pHead1->val <= pHead2->val) {
           pHeadNew = pHead1;
           pHeadNew->next = Merge(pHead1->next, pHead2);
       } else {
           pHeadNew = pHead2;
           pHeadNew->next = Merge(pHead1, pHead2->next);
       }
        return pHeadNew;
    }
};

反思:看到比较繁杂的题目,想想能不能用递归:

不用递归的情况:递归有大量重复计算,栈深度大

用递归:操作重复,但递归计算不重复。

啥也不说了,我要返回去把上一道题反转链表用递归做一下去 ~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值