leetcode 21 合并两个有序链表 C语言版本python版本(待续)

https://leetcode-cn.com/problems/merge-two-sorted-lists/

21. 合并两个有序链表【简单】

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

from 花花酱
算法思路 花花酱 https://www.bilibili.com/video/av27109196?t=230

C++基础版

Iterative 版 代码效率:28ms/8.9M

struct ListNode{
    int val;
    ListNode *next;
    ListNode(int x):val(x),next(NULL){}
};

class Solution{
    public:
    ListNode* mergeTwoList(ListNode* l1,ListNode* l2){
        ListNode dummy(0);
        ListNode* tail = &dummy;
        while(l1 && l2){
            if(l1->val<l2->val){
                tail->next = l1;
                l1 = l1->next;
            }
            else{
                tail->next = l2;
                l2 = l2->next;
            }
            tail =tail->next;
        }
        if(l1) tail->next = l1;
        if(l2) tail->next = l2;

        return dummy.next;
    }
}

疑问tips:

  1. 为什么最后一个返回可以用dummy.next 而不是dummy->next
  2. ListNode* 和ListNode有什么区别
  3. dummy(0)为什么要0 ,代表什么
  4. 函数的数据类型为什么定义成ListNode*
  5. 为什么要返回dummy.next,不应该返回dummy的头么?
  6. 怎么计算算法复杂度

A:
1 对于一个结构体,如果声明一个变量,例如题目中的NodeList dummy(0),这里的意思是声明一个dummy结构体变量,初始化为0.如果要取结构体变量里面的值,需要用’.'的方式取,例如dummy.next就是取这个结构体变量里面的next指针。但是如果声明的是一个结构体指针,例如NodeList dummy2,结构体指针可以用’->‘的方式取这个指针指向的变量的结构体内的值,例如dummy2->next。使用’.‘和使用’->'分别是对结构体变量和结构体指针而言的,有区别。所以题目中用dummy.next
2 ListNode
和ListNode声明的变量的性质是不一样的。ListNode声明的是一个普通的变量,这个变量里面包含了ListNode的所有结构体信息;而使用ListNode声明的是一个指针,一个指向结构体的指针。
3 dummy(0)应该是声明一个变量dummy时对其进行初始化,也就相当于ListNode dummy;dummy.val = 0;这种写法应该是应用了C++类的特性的一种写法。在c里面这样写可能会出错。
4 函数的数据类型定义成ListNode
,这个说法有些欠妥,因为这里说的是函数的返回值是一个ListNode的指针类型。再例如定义一个函数int f(int a);,指的是要求这个函数返回一个int类型的值,如果定义成int f(int a);指的是要求函数返回一个int类型的指针。这种定义和题目中的定义ListNode* mergeTwoList()是一回事。函数指针也是有的,就是指向函数的指针。
5 这段代码是要将两个链表合并,也就是说返回的链表的第一个结构体元素应该是l1或者l2的第一个结构体元素,但是代码中写的第一个元素是将l1和l2中值较小的那个元素的地址赋值给了dummy.next,也就是说dummy指向的下一个元素就是l1和l2中最小的元素,这样说来,必须返回dummy指向的下一个元素才是l1、l2中的第一个元素。如果真的直接返回dummy的头,那么头的值应该是0才对,而不是l1或者l2的头
6 复杂度一般有时间复杂度和空间复杂度。计算复杂度一般都需要有一个输入规模,比如说排序,输入规模可以是序列的长度n,本题的输入规模可以认为是两个链表的长度m、n,时间复杂度就是说在输入规模下需要计算多长时间,可以大约等效为计算加减法、乘除法、或者循环的次数。例如本题要想把两个长度为m、n的序列合并,按照这个算法,是一个一个对比,对比的次数就是序列比较短的那个链表的长度。那么这本题的时间复杂度为o(min{m,n})。空间复杂度说的是在计算过程中所需要的内存大小的规模,也就是内存的开销,这个和时间复杂度一样,是和输入规模有关的。例如本题的算法中就只声明了一个ListNode变量和ListNode指针,其他全是指针操作,没有其他内存开销,说明内存开销和输入规模没关系,那么空间复杂度可以认为是o(1)

ps:感谢学霸的帮忙解答。


改编为python版本

class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution(object):
    def mergeTwoLists(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        dummy = ListNode(0)
        tail = dummy
        while(l1 and l2):
            if(l1.val<l2.val):
                tail.next = l1
                l1 = l1.next
            else:
                tail.next = l2
                l2 = l2.next
            tail = tail.next
        if l1:
            tail.next = l1
        if l2:
            tail.next = l2
        return dummy.next

以上python版本为我根据花花的c++ 基础版本改编的。
tip:

  1. 什么时候变量表示ListNode 什么时候表示一个数字
  2. dummy = ListNode(0) 这一句是否就是定义了一个链表
  3. tail = dummy这一句是只传递了一个位置过来么
  4. 弱鸡问一句 怎么自己运行已经写好的类函数

C++改进版本

recirsive 28s/8.9M
通过递归的方法进行改进,改进的想法如下:
递归方法

struct ListNode{
    int val;
    ListNode *next;
    ListNode(int x):val(x),next(NULL){}
};

class Solution{
    public:
    ListNode* mergeTwoLists(ListNode* l1,ListNode* l2){
        if(!l1||!l2)return l1 ? l1 : l2;
        if(l1->val < l2->val){
            l1->next = mergeTwoLists(l1->next,l2);
            return l1;
        }
        else{
            l2->next = mergeTwoLists(l2->next,l1);
            return l2;
        }
    }

};

这个版本代码更为简单,需要理解递归。

改编为python版本

class ListNode(object):
    def __init__(self,x):
        self.val = x
        self.next =None


class Solution(object):
    def mergeTwoLists(self, l1, l2):
        if (l1 and l2): 
            if (l1.val<l2.val):
                l1.next = mergeTwoLists(l1.next,l2)
                return l1
            else:
                l2.next = mergeTwoLists(l1,l2.next)
                return l2
        else:
            if l1:
                return l1 
            else:
                return l2

tips:
1 python 代码尚未正确运行
2 不知道怎么判断链表为空
3 不知道怎么一次性注释和解注释多行代码
4 不知道怎么在环境运行类程序

python数据结构链表之单向链表

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值