Leetcode的第2题,持续改进算法到cleancode

44 篇文章 0 订阅
24 篇文章 1 订阅
这是非常典型的,同样是编代码完成一样的功能,基础也够,但是写出来的速度、容易度、可阅读性、简洁性差异极大。这得看天赋和经验,绝不是简单搬砖。这是历来强调clean code和代码质量的一个原因。
方法上教训自己的就是多看、多读、编码前多构思,不要凭着冲劲儿蛮干。

titile

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

第1版,直接按照加法累加,搬移2个listnode到第三个,58line

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

def judgeSym(x, bit, y = 0):
    #判断三个数和是否大于等于10,返回值和进位符
    tmp = x + y + bit
    if  tmp >= 10 :
        return tmp-10, 1
    else:
        return tmp, 0

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        rst = []
        bit = 0
        while (l1.next and l2.next):
            x,bit = judgeSym(l1.val, bit, l2.val)
            rst.append(x)
            l1 = l1.next
            l2 = l2.next
        
        #最后一个值别忘记累加,没有next但是有当前的val
        x, bit = judgeSym(l1.val, bit, l2.val)
        rst.append(x)

        l1 = l1.next
        l2 = l2.next

        if l1:
            while(l1.next):
                x, bit = judgeSym(l1.val, bit)
                rst.append(x)
                l1 = l1.next
            x,bit = judgeSym(l1.val, bit)
            rst.append(x)
        
        if l2:
            while(l2.next):
                x, bit = judgeSym(l2.val, bit)
                rst.append(x)
                l2 = l2.next
            x,bit = judgeSym(l2.val, bit)
            rst.append(x)


        if bit > 0:
            rst.append(bit)
        
        h = ListNode(rst[0])
        y = h
        for it in rst[1:]:
            y.next = ListNode(it)
            y = y.next

        return h

第2版,查看长度,累加到长的链表上,避免多个while去盲做,63line

# 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:
        """
        参考leetcode不错的简洁思路:契合链表这种算法结构,且有效利用了输入的节点;
        影响是改变了输入的节点值;
        1)计算两个listnode,如果l1比l2短,交换他们,确保l1总是小于l2;
        2)这样同时遍历l1、l2(l2短,以它截止为准),值加到l1上,注意进位处理
        
        :param l1:
        :param l2:
        :return:
        """
        if self.getLen(l2) > self.getLen(l1):
            l1, l2 = l2, l1

        head = l1
        tail = 0
        while l2:
            l1.val = l1.val + l2.val + tail
            if l1.val >= 10:
               l1.val -= 10
               tail = 1
            else:
               tail = 0
            if l1.next:
               l1 = l1.next
            elif tail:
               l1.next = ListNode(1)
               l1 = l1.next
               tail = 0

            l2 = l2.next 
            
        #l1的进位没有处理完,防止出现9999 增加1之后全部进位,尾部可能新增1个
        while tail:
            l1.val += tail
            if l1.val >= 10:
                l1.val -= 10
                tail = 1
            else:
                tail = 0

            if l1.next:
                l1 = l1.next
            elif tail:
                l1.next = ListNode(1)
                tail = 0
                l1 = l1.next
            
        return head

    def getLen(self, l1:ListNode)->int:
        length = 0
        while(l1):
            length += 1
            l1 = l1.next
        return length

第3版,判决长度,进位分离开单独做,49line

# 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:
        """
        参考leetcode不错的简洁思路:契合链表这种算法结构,且有效利用了输入的节点;
        影响是改变了输入的节点值;
        1)计算两个listnode,如果l1比l2短,交换他们,确保l1总是小于l2;
        2)这样同时遍历l1、l2(l2短,以它截止为准),值加到l1上,注意进位处理
        特别注意,进位的处理分离出来会非常有利,少判断很多条件,解耦listnode的next方法;很clean code
        :param l1:
        :param l2:
        :return:
        """
        if self.getLen(l2) > self.getLen(l1):
            l1, l2 = l2, l1

        head = l1
        while l2:
            l1.val = l1.val + l2.val
            l1 = l1.next
            l2 = l2.next
            
        #l1的进位没有处理完,防止出现9999 增加1之后全部进位,尾部可能新增1个
        p = head
        while p:
            if p.val >=10:
                p.val -= 10
                #自然而然的进位,下一个存在就next并值递增,否则到了尾巴,新建一个listnode赋值1,并连缀到l1尾巴上
                if p.next:
                    p = p.next
                    p.val += 1
                else:
                    p.next = ListNode(1)
            else:
                p = p.next
            
        return head

    def getLen(self, l1:ListNode)->int:
        length = 0
        while(l1):
            length += 1
            l1 = l1.next
        return length

commit

  • 功能都ok,但是完成速度和烧脑性逐个变快、变简;可读性变好
  • 两个关键:2个数、多个结构体,长度、类型等属性不以操作,首先判决后找最大的那个累积操作,而不要一直做下去,结束做判断
  • 特殊条件的特别操作,可以集中处理,免于叠加处理的开销和增加复杂。如这里的进位,分离处理快速、方便、逻辑也比较严谨。而第二版,融合进a+b处理就要反复考虑进位、链表延长等问题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值