LeetCode 边做边学(2) -链表相加

题目来自LeetCode:

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. You may assume the two numbers do not contain any leading zero, except the number 0 itself.

  • 给定两个非空链表,代表非负整数.数字以相反的顺序存储,每个节点包含一个数字.写出代码使两数相加并返回一个链表.(您可以假设这两个数字前项不包含任何零,除了数字0本身)

示例:

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.

# Definition for singly-linked list. 此为给定的单链表定义
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        
思考:
  • 这道题,很明显是考察链表的.基本的单链表,不去考虑最开始的head与最末尾的tail的话,一个链表的node包含两部分,一部分为存放数值的value部分,一部分为指向下一个node的类似指针部分.在此代码中预先给出了单链表的类定义,表明了基本写法.我们不用专门去定义head 或者tail,链表的head可以直接在self.val中赋值,链表的结尾可以把self.next设为none.
  • 此题的难点是链表为逆序存储,在链表相加的时候需要考虑进位情况.

方法 一:

想到先可以分成三步:

  • 把链表转换为List,
  • 把两List相加
  • 再把list转换为链表
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        # print(l1.val)
        L1 = self.readlist(l1)
        L2 = self.readlist(l2)
        total = self.addlist(L1,L2)
        # print(total)
        return self.toListNode(total[::-1])
        
              
    def readlist(self,l):
    ```
   	把链表转化为list
    ```
        tolist = []
        while True:
            # print(l.val)
            tolist.append(l.val)
            # print(tolist)
            if l.next == None:
                return tolist
            l = l.next

    def toListNode(self,L):
    ```
    把list转化为链表
    存储过程为先给最后一个节点赋值,依次往前,
    直到找到最开始的节点
    L[0]保存在了末位节点,正好与方法二反过来
    ```

        for i in range(len(L)):
            A = ListNode(L[i])
            if i ==0:
                A.next = None
            else:
                A.next = B
            B = A
            
        return A
    
    def addlist(self,L1,L2):
        total = []
        if len(L2)>len(L1):
            L2,L1 = L1,L2
        forward = 0
        for i in range(len(L1)):
            a = L1[i]
            if i >=len(L2):
                b = 0
            else:
                b = L2[i]
                
            # if a+b+forward>9:
            value = (a+b+forward)%10
            forward =(a+b+forward)/10
            total.append(value)
        if forward >0:
            total.append(forward)
        return total

第一种方法比较笨拙,但是很直观.

提高

方法 二:

仔细分析则会发现,原来通过链表的构建方式,我们知道:链表的第一个节点的值代表了各位,第二个节点的值代表了百位,以此类推.那么一开始以为的链表逆序会阻碍运算的想法,发现其实是错误的.链表逆序排列提供了正序相加(包含进位)的便利.
在这里插入图片描述
此方法首先定义一个初始节点存值为0, 为了保存节点,因此赋值给root变量.节点存取的数值按照输入链表的顺序顺序写入.即

  • 先计算两个链表 个位数的值A1
  • 声明ListNode()存入A1值,并用初始节点n.next 指向此节点
  • 把新生成的节点(存有数值A1)作为新的 n
  • 依此循环,把存有A2数的节点再赋值给 n.next
  • 最后,由于返回的起始节点应为存有A1的节点,所以返回 n.next

代码如下:

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

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        carry = 0
        root = n = ListNode(0)
        while l1 or l2 or carry:
            v1 = v2 = 0
            if l1:
                v1 = l1.val
                l1 = l1.next
            if l2:
                v2 = l2.val
                l2 = l2.next
            carry, val = divmod(v1+v2+carry,10)
            n.next = ListNode(val)
            n = n.next
        return root.next
思考

两种方法在存储节点时有不同.

  • 第一种: 先生成A,再生成B,把A赋值给新生成的B.next,代表了B可以指向A.因此数值会被先存放在最后一个节点处,然后依次往前存储,直到结束.那么最后生成的节点即为起始节点

  • 第二种: 先生成A,再生成B,把新生成的B赋值给A.next,代表了A可以指向B.因此数值会被先存放在最开始的节点处,然后依次往后存储,直到结束.那么最后生成的节点即为末尾节点.

第二种方法在进行加法运算上具有的优势:
在进行两数相加的运算中最容易忽视的就是进位,与相加类型需要注意的是:

  • 进位的值不单单可以等于 1, 也可以等于2. 因此用求商运算最为保险, 商即为进位数值,余数为此位得数.
  • 进位可以导致最终和的长度可能会大于两个加数的位数. 因此要确保最高位的和 > 10时 有相应的进位.
  • 由于None type 不能与int type 进行相加,所以应做判断.保证不会出现错误格式相加

此题增加难度的话可以改为链表中的数值正序存储.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值