[LeetCode]C语言-Merge k Sorted Lists-程序优化之路

这道题要求将k个已排序的链表合并,刚开始看到这个题,首先想到是它上一个题将两个有序链表合并(主要通过一个while循环判断两个链表元素值中哪个大,然后就链接那个链表元素),我接着想直接定义一个链表让它与每一个链表通过调用函数合并,最后就能得到结果。

224ms

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
    struct ListNode* head = NULL;
    struct ListNode* ans = NULL;
    
    if(l1 == NULL && l2 == NULL) {
        return ans;
    }
    else if(l1 != NULL && l2 == NULL) {
        return l1;
    }
    else if(l2 != NULL && l1 == NULL) {
        return l2;
    }

    if(l1->val <= l2->val) {
        head = l1;
        l1 = l1->next;
    }
    else {
        head = l2;
        l2 = l2->next;
    }
    
    ans = head;
    
    while(l1 != NULL && l2 != NULL) {
        if(l1->val <= l2->val) {
            head->next = l1;
            head = head->next;
            l1 = l1->next;
        }
        else {
            head->next = l2;
            head = head->next;
            l2 = l2->next;
        }
    }
    while(l1 != NULL){
        head->next = l1;
        head = head->next;
        l1 = l1->next;
    }
    while(l2 != NULL){
        head->next = l2;
        head = head->next;
        l2 = l2->next;
    }
    return ans;
}
struct ListNode* mergeKLists(struct ListNode** lists, int listsSize) {
    struct ListNode* ans = NULL;
    int i = 0;

    if(listsSize == 0) {
        return NULL;
    }
    else if(listsSize == 1) {
        return lists[0];
    }
    else {
        ans = mergeTwoLists(lists[0], lists[1]);
    }
    for(i=2; i<listsSize; i++) {
        ans = mergeTwoLists(ans, lists[i]);
    }
    return ans;
}

直接运行通过,还是很高兴,但是看到运行时间居然是两百多毫秒,这让我这个强迫症患者如何能接受得了,我就开始优化代码。首先肯定找执行次数最多的地方—for循环里面的语句,每次循环就调用mergeTwoLists函数,接着我想或许这个函数有问题,通过一段时间仔细查看,终于发现冗余的地方,那就是函数末尾两个while循环,它本来处理当其中一个链表结束,另一个剩余链表元素。但是这项工作只需运行一次就能实现,而无需重复多次运行,最后我将while改成if,果然大大减少了运行时间。

124ms

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
    struct ListNode* head = NULL;
    struct ListNode* ans = NULL;
    
    if(l1 == NULL && l2 == NULL) {
        return ans;
    }
    else if(l1 != NULL && l2 == NULL) {
        return l1;
    }
    else if(l2 != NULL && l1 == NULL) {
        return l2;
    }

    if(l1->val <= l2->val) {
        head = l1;
        l1 = l1->next;
    }
    else {
        head = l2;
        l2 = l2->next;
    }
    
    ans = head;
    
    while(l1 != NULL && l2 != NULL) {
        if(l1->val <= l2->val) {
            head->next = l1;
            head = head->next;
            l1 = l1->next;
        }
        else {
            head->next = l2;
            head = head->next;
            l2 = l2->next;
        }
    }
    if(l1 != NULL) {
        head->next = l1;
    }
    if(l2 != NULL) {
        head->next = l2;
    }
    return ans;
}

虽然已经减少一半了,但是还没到最好的8ms,对于我这个强迫症患者还是不舒服斯基,于是我继续代码优化,首先我认为mergeTwoLists函数已经没法优化了,那就只能优化主函数,当我实在没办法的时候,我看了一下leetcode后面解决思路,一下子明白问题出在哪,我这个程序以ans链表为主,使其不断与其它链表合并,带来的后果是ans链表越来越长,for循环越到后面,mergeTwoLists函数会花费越来越多时间。而替换方案是,每两个链表合并,得到一组新链表,然后再次两两合并,这样循环下去。两种方案虽然mergeTwoLists函数调用次数无太大区别,但是前一种每次循环就增加时间,而第二种是每次所有链表两两合并后增加时间,比前一种减少了大量累加时间。

8ms

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
    struct ListNode* head = NULL;
    struct ListNode* ans = NULL;
    
    if(l1 == NULL && l2 == NULL) {
        return ans;
    }
    else if(l1 != NULL && l2 == NULL) {
        return l1;
    }
    else if(l2 != NULL && l1 == NULL) {
        return l2;
    }

    if(l1->val <= l2->val) {
        head = l1;
        l1 = l1->next;
    }
    else {
        head = l2;
        l2 = l2->next;
    }
    
    ans = head;
    
    while(l1 != NULL && l2 != NULL) {
        if(l1->val <= l2->val) {
            head->next = l1;
            head = head->next;
            l1 = l1->next;
        }
        else {
            head->next = l2;
            head = head->next;
            l2 = l2->next;
        }
    }
    if(l1 != NULL) {
        head->next = l1;
    }
    if(l2 != NULL) {
        head->next = l2;
    }
    return ans;
}
struct ListNode* mergeKLists(struct ListNode** lists, int listsSize) {
    struct ListNode* ans = NULL;
    int i = 0;
    
    if(listsSize == 0) {
        return NULL;
    }
    else if(listsSize == 1) {
        return lists[0];
    }
    else {
        while(listsSize > 1) {
            for(i=0; i<listsSize/2; i++) {
                lists[i] = mergeTwoLists(lists[listsSize-i-1], lists[i]);
            }
            if(listsSize % 2 != 0) {
                lists[i-1] = mergeTwoLists(lists[i-1], lists[i]);
            }
            listsSize = listsSize / 2;
        }
        ans = lists[0];
    }
    
    return ans;
    
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值