LeetCode刷题笔记(Python3)——2. 两数相加
(点击查看题目)(点击查看官方题解)

官方题解中这次没有直接给出可粘贴使用的Python代码,但官方的题解视频中使用的就是Python代码,可以参考。


LeetCode刷题笔记(Python3)——2. 两数相加

  • 初始解法
  • 优化解法:
  • 1. Python的特殊赋值方法
  • 2. Python中None的真假
  • 3. Python运算符
  • 4. 过长代码行的换行
  • 简短解法:
  • 5. 条件语句的两类用法
  • 6. 链表的定义
  • 7. 推荐使用Pycharm写代码,个人觉得比Spyder好用
  • 8. Pycharm的两种常用快捷键


初始解法

# 时间复杂度:O(max(M,N)) 空间复杂度:O(max(M,N))
class Solution:
    def numCarry(cur_node):   # 进位函数
        if cur_node.val >= 10:
            cur_node.val -= 10
            return 1
        else:
            return 0

    def addOneAtEnd(cur_node):  # 最高位进1函数
        new_node = ListNode()
        new_node.val = 1
        cur_node.next = new_node

    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        flag_l1_end = 0  # l1结束标志
        flag_l2_end = 0  # l2结束标志
        flag_carry  = 0  # 进位标志

        result = ListNode()
        cur_node = result

        while 1:
            new_node = ListNode()
            cur_node.next = new_node
            cur_node = new_node

            if flag_l1_end:  # l1已经结束
                cur_node.val = l2.val + flag_carry
                flag_carry = Solution.numCarry(cur_node)
                if l2.next is None:
                    if flag_carry:
                        Solution.addOneAtEnd(cur_node)
                    return result.next
                l2 = l2.next
            elif flag_l2_end:  # l2已经结束
                cur_node.val = l1.val + flag_carry
                flag_carry = Solution.numCarry(cur_node)
                if l1.next is None:
                    if flag_carry:
                        Solution.addOneAtEnd(cur_node)
                    return result.next
                l1 = l1.next
            else:  # l1和l2均未结束
                cur_node.val = l1.val + l2.val + flag_carry
                flag_carry = Solution.numCarry(cur_node)

                if l1.next is None:
                    flag_l1_end = 1
                else:
                    l1 = l1.next

                if l2.next is None:
                    if flag_l1_end:
                        if flag_carry:
                            Solution.addOneAtEnd(cur_node)
                        return result.next
                    else:
                        flag_l2_end = 1
                l2 = l2.next

这个解法虽然没错,效率也不低,但由于很久不写Python代码,很多基本操作都忘记了,导致代码过于啰嗦。官方解法给出的优化解法如下。

优化解法:

# 时间复杂度:O(max(M,N)) 空间复杂度:O(max(M,N))
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        head = point = ListNode() # 表头
        carry = 0  # 进位

        while l1 or l2:
            new_node = ListNode()
            if not l1:  # l1已经结束
                sum_ = l2.val + carry
                new_node.val = sum_ % 10
                carry = sum_ // 10
                l2 = l2.next
            elif not l2:  # l2已经结束
                sum_ = l1.val + carry
                new_node.val = sum_ % 10
                carry = sum_ // 10
                l1 = l1.next
            else:  # l1和l2均未结束
                sum_ = l1.val + l2.val + carry
                new_node.val = sum_ % 10
                carry = sum_ // 10
                l1 = l1.next
                l2 = l2.next

            point.next = new_node
            point = new_node
        if carry:  # 最高位前还需要进1
            point.next = ListNode(1)
        return head.next

1. Python的特殊赋值方法

a = b = c  = 1 # 相当于其他编程语言中的 c = 1, b = c, a = b
a, b = 1, 'hello'  # 对应赋值,基本相当于其他编程语言中的 a = 1, b = 'hello'
a, b = b, a  # 对应赋值的特殊用法,相当于交换变量a和b的值

注意:Python中的 “a, b = b, a”之所以相当于交换变量a和b的值,是因为a = b和b = a这两个操作是同时而非顺序进行的。

2. Python中None的真假

  1. Python 中 0 为假,大小为 0 的容器也定义为假。所以空字符串与空的列表也为假。
  2. None 可作为一个对象,该对象的类型为NoneTye。None 表示的含义,更多的是一种不存在,是真正的空,而不是空列表([])的空,例如一个函数的没有返回值。
# 几个例子
not None  # False
None == None  # True
None is None  # True
[] == None  # False
[] is None  # False

注意:参考博客中有一处 “错误”(也可能是Python后来做了修改)。None不能与数字做比较。如果出现此类比较,如“1 > None”系统将提示
TypeError: ‘>’ not supported between instances of ‘int’ and ‘NoneType’

3. Python运算符

长时间不写Python,像“//”(整除)、“**”(幂)、“!=”(不等于)等很多基本运算符都忘记了。具体可以参考菜鸟教程:Python运算符

# 几个例子
5 // 2  # 2
2 ** 3  # 8
1 != 2  # True

注意:不等号“<>”已经被Python3废弃,应该使用“!=”替代。

4. 过长代码行的换行

在需要换行的位置使用反斜杠“\”后直接换行即可。

a = 1 + \
    2  # a = 3

上述代码已经是在题解中浏览到的最好的代码了。不过,如果追求代码的简洁,还可以采用下面这种更尖端的解法(并没有更快,只是更帅哈哈 😃 )。

简短解法:

# 时间复杂度:O(max(M,N)) 空间复杂度:O(max(M,N))
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        cur = head = ListNode(l1.val + l2.val)
        while l1.next or l2.next:
            l1 = l1.next if l1.next else ListNode()
            l2 = l2.next if l2.next else ListNode()
            cur.next = ListNode(l1.val + l2.val + cur.val // 10)
            cur.val = cur.val % 10
            cur = cur.next
        if cur.val >= 10:
            cur.next = ListNode(cur.val // 10)
            cur.val = cur.val % 10
        return head

5. 条件语句的两类用法

上述代码简洁的一个关键就是条件语句的另一种用法。

常见用法

if 判断条件1:  # 不要忘记使用冒号
	执行语句1
elif 判断条件2:
	执行语句2
elif 判断条件3:
	执行语句3
else:
	执行语句4

特殊用法

a = 1 if 判断语句 else 2

此时,如果判断语句为真,则执行 a = 1;否则将执行 a = 2。

6. 链表的定义

通过系统的提示,可以学习Python中如何定义链表。

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

7. 推荐使用Pycharm写代码,个人觉得比Spyder好用

以前写Python代码全用的是Spyder,但最近用Pycharm发现Pycharm会提示很多代码规范性的东西,有助于帮助自己把代码写得更规范、清晰、易懂。

例如,如果函数用了大写字母,系统会提示“Function name should be lowercase”(函数名应该使用小写字母);如果两个函数的定义之间只间隔了一行,那么系统会提示“expected 2 blank lines”(期望有两个空行)等等。

因此,个人更倾向于推荐使用Pycharm来写代码。

8. Pycharm的两种常用快捷键

  1. 注释/取消注释:选中后,“Ctrl + /”。无论单行多行,都是这一个快捷键。
  2. 撤销/恢复:“Ctrl + z”/“Ctrl + Shift + z”。后者会与搜狗输入法中“符号大全”的快捷键冲突,建议在搜狗输入中将“符号大全”的快捷键修改为“Ctrl + Shift +x”,这样与一般的快捷键都不会冲突且改动不大。