Python LeetCode:中等题 2、两数相加(两种思路+优化代码+高端操作+形象比喻+细致解析)

2、两数相加

在这里插入图片描述

坑爹点:

1、此题代码区会给出给出一段注释,这段注释是为了方便大家理解ListNode这一个类的定义的。LeetCode内置代码已经完成了ListNode这一个类的编写,不需要把这一段取消注释然后直接使用,否则会报错xxx is not valid value for the expected return type ListNode
在这里插入图片描述
2、两个链表长度不一定相同。
3、输入的链表和输出的链表都是逆序的!
题目给出的三个示例都是顺序和逆序结果相同的。看不仔细就会被坑,比如我。。

简单思路:

1、直接两数相加

就是把链表转换为数,再把两个数求和再转换为链表。
这里用最直观的方式写的,不求时间内存和简洁,只求清晰明白。
上代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        number1 = 0
        i = 0
        while l1 != None:
            number1 += l1.val * 10 ** i
            l1 = l1.next
            i += 1
        
        number2 = 0
        i = 0
        while l2 != None:
            number2 += l2.val * 10 ** i
            l2 = l2.next
            i += 1

        number_out = str(number1 + number2)[::-1]
        node = [ListNode() for i in range(len(number_out))]
        for i in reversed(range(len(number_out))):
            if i == len(number_out)-1:
                node[i].next = None
            else:
                node[i].next = node[i+1]
            node[i].val = int(number_out[i])
        return node[0]

BinGo!
在这里插入图片描述

2、当链表题做

思路一直接求和其实并不太高效,但是重在简单。还可以用链表的方式来做,把两个给定链表每个节点的数相加再构建新链表输出即可。这里要考虑进位和连续进位的情况。
贴一下原代码,非常好理解:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        add_1 = 0 # add_1和add_2是定义的两个进位标志位。1表示下一位置进位,2表示当前节点位置进位。
        add_2 = 0
        out_list = [] # 定义的输出列表。
        while l1 != None or l2 != None or add_2 == 1:
            try:
                value_1 = l1.val
                l1 = l1.next
            except AttributeError: # 当无下一节点时取值为0。下同。
                value_1 = 0
            try:
                value_2 = l2.val
                l2 = l2.next
            except AttributeError:
                value_2 = 0
            temp = value_1 + value_2 + add_2
            if temp >= 10:
                add_1 = 1
                temp %= 10
            out_list.append(temp)
            add_2 = add_1 # 节点位置的移动。
            add_1 = 0

        node = [ListNode() for i in range(len(out_list))]
        for i in reversed(range(len(out_list))):
            if i == len(out_list)-1:
                node[i].next = None
                node[i].val = int(out_list[i])
            else:
                node[i].next = node[i+1]
                node[i].val = int(out_list[i])
        return node[0]

BinGo!

在这里插入图片描述
自己都觉得自己写的太复杂了,下面贴出优化后的思路和代码。

3、优化思路

先上代码,后面给出解析。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        add = 0
        result = ListNode()
        temp_1 = result
        while l1 != None or l2 != None or add == 1:
            if l1 != None:
                value_1 = l1.val
                l1 = l1.next
            else:
                value_1 = 0
            if l2 != None:
                value_2 = l2.val
                l2 = l2.next
            else:
                value_2 = 0
            temp_2 = ListNode(value_1 + value_2 + add)
            add = 0
            if temp_2.val >= 10:
                add = 1
                temp_2.val %= 10
            temp_1.next = temp_2
            temp_1 = temp_2
        return result.next

在这里插入图片描述
求和进位都是很简单的操作了,这里主要写一下构造链表的过程,以题目示例1为例来描述一下链表构造中内部各个变量的变化,以此来理清思路。
①初始化 result 变量。
在这里插入图片描述
②令 temp_1 指向 result。
在这里插入图片描述
③初始化变量 temp_2,其值设定为7。
在这里插入图片描述
④使 temp_1.next 指向 temp_2,由于 temp_1和 result 指向同一个内存,temp_1 改变,result 也随之改变。
在这里插入图片描述
⑤修改 temp_1的指向,让 temp_1指向 temp_2,即 result.next。
在这里插入图片描述
⑥重修初始化 temp_2,其值设定为0。
在这里插入图片描述
⑦将temp_1.next 指向 temp_2,相应的,result也会发生改变。
在这里插入图片描述
⑧修改 temp_1 ,使 temp_1 指向 temp_2, 即 result.next,next。
在这里插入图片描述
⑨重新初始化变量 temp_2,其值设定为8。
在这里插入图片描述
⑩、⑪同上重复操作。
在这里插入图片描述

在这里插入图片描述
⑫返回 result.next 即为所求。
在这里插入图片描述

需要注意的是:

Python中如果给变量赋的值是不可变变量,比如整型、字符串、元组,那么是将变量指向这个值所在的内存,对变量进行改变会让变量指向一个新的值的内存地址,而不会改变原内存地址处的值。
比如 a=1, a+=1这两条语句。第一条语句执行让变量 a 指向 1 所在的内存地址,而第二条语句会让 a 指向 2 所在的内存地址。在这个过程中原来 1 内存地址处存放的还是1。
如下( id() 命令可以获取内存地址):
在这里插入图片描述
而如果给变量赋的是可变变量,比如列表、字典、自定义的类(比如上面这个题)等,对变量进行改变会让这个变量指向的内存地址的值发生改变,而不会改变内存地址。
比如 a=[1],a[0]+=1 这两条语句。第一条语句为变量 a 开辟一个新的内存地址,该内存里存放 [1] ,第二条语句会改变这个内存地址里面的值,将 [1] 变成 [2] ,但地址是没有改变的。
如下:
在这里插入图片描述
这样也就好解释以下现象的出现:
在这里插入图片描述在这里插入图片描述
学霸题,你学会了吗?
这也就是上题中 result 会发生改变的原因。

最后用我形象的比喻来描述一下上面链表创建的过程

在这里插入图片描述这,是一个节点。
在这里插入图片描述
形象化一点,节点像不像一块积木(一个独立节点next为空,不妨把这个位置空出来)。
在这里插入图片描述好了,这就是抽象出来的一块积木。比如左图是#号积木。

那么现在就可以玩儿游戏了,如下有三块积木,需要按照7-0-8的顺序拼插在一起。
在这里插入图片描述
第一步:一只手按住7号积木,同时准备好0号积木。
在这里插入图片描述

第二步:把0号积木插到7号积木的后面。
在这里插入图片描述
第三步:手移到0号积木上,按住0号积木;准备好8号积木。
在这里插入图片描述
第四步:把8号积木插到0号积木后面。完成拼插。
在这里插入图片描述
对比积木拼插过程和上面12张图的链表创建过程,你学会了吗?

填空题:请在以下三个位置填入适当的变量名称(答案见篇尾)。

在这里插入图片描述

拓展内容:如果要顺向拼积木怎样操作?

第一步:用手按住7号积木,准备好0号积木。
在这里插入图片描述
第二步:把0号积木插在7号积木的前面。
在这里插入图片描述
第三步:把手移到0号积木上,按住0号积木;准备好8号积木。
在这里插入图片描述
第四步:把8号积木插在0号积木前面,完成拼插。
在这里插入图片描述
如下:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        add = 0
        temp_2 = ListNode()
        while l1 != None or l2 != None or add == 1:
            temp_1 = ListNode()
            if l1 != None:
                value_1 = l1.val
                l1 = l1.next
            else:
                value_1 = 0
            if l2 != None:
                value_2 = l2.val
                l2 = l2.next
            else:
                value_2 = 0
            temp_2.val = value_1 + value_2 + add
            add = 0
            if temp_2.val >= 10:
                add = 1
                temp_2.val %= 10
            temp_1.next = temp_2
            temp_2 = temp_1
        return temp_1.next

在这里插入图片描述
——————————————————————————————
本文禁止自行转载!盗版必究!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值