LeetCode第二题:两数相加(Add Two Numbers)

LeetCode第二题:两数相加(python,java)

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.
Example:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
本题涉及到linked list(链表)。本文不对链表本身做过多讨论,等以后遇到类似的题再做深究。本文就题论题,只讨论本题所用的最简单的单链表形式。

一、Python链表知识储备

本节部分图源来自:
https://www.cnblogs.com/kumata/p/9147077.html
在直接贴出代码前,我觉得一个更重要的任务是理一下Python中什么是链表。要注意到不是我们常见的list(列表)。链表作为一种基本的数据结构存储形式,到底是什么呢?
不妨先来看一下LeetCode第一题与第二题,分别用了两种数据结构,数组与链表。
那么来看一下二者。在Python中,数组用list[]表示,而list的各种方法我就不多提了。那么链表呢?Python用的是ListNode类。

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

链表是通过一个个节点(Node)组成的,每个节点都包含了称为数据域(value)和指针域(next)的基本单元,它也是一种递归的数据结构。它能保持数据之间的逻辑顺序,但存储空间不必按照顺序存储。
在这里插入图片描述
对上图做一些说明:
节点 :每个节点有两个部分,左边部分称为值域,用来存放用户数据;右边部分称为指针域,用来存放指向下一个元素的指针。
head :head节点永远指向第一个节点
tail : tail永远指向最后一个节点
None :链表中最后一个节点的指针域为None值

现在有了这些知识做铺垫。那么上面的代码段应该比较好理解了。上面的类实际上实现的是一个单独的节点,而一个链表是由若干个节点组成的。现在来看看到底什么是链表:

# !/usr/bin/python3
# -*-coding:UTF-8-*-
# By WILL
class ListNode():
    def __init__(self,x,next=None):
        self.val = x
        self.next = next
#l1就是一个链表(虽然这里是一个node,通过对next赋值不断扩充链表)
l1 = ListNode(1)
print(hex(id(l1)))#查看当前l1的地址的十六进制表示
l1.next = ListNode(4)
l1.next.next = l3 =ListNode(56)#当然这样写.next.next不太美观。。。
l3.next = l4 = ListNode(89)
print(l1)#第一种打印方式,试试看
while l1:#第二种。很像c++和java的数组打印元素的方式。Python数组就直接print就行。
    print(l1.val)
    l1 = l1.next

来看运行结果:

0x10bf0f6d8
<__main__.ListNode object at 0x10bf0f6d8>
1
4
56
89

这里做一些笔记:
1.关于赋值语句:

l3.next = l4 = ListNode(89)
a =b =1
a = b =c =2

这三种语句的赋值先后顺序。前面两句是一样的,以a =b =1为例,是
a=1,然后b =a .所以本例中,是ListNode(89)=l3.next 。然后l4 =l3.next。同样,最后的先后循序是:a=2,b=a,c=a。
2.关于链表与链表第一个node的关系:
我们说一个链表其实指的是链表的head指向的node,也就是第一个node所在的地址或者叫元素。为什么要说这些呢?后面代码实现时候,返回的要求是一个链表,但是我们只需要返回第一个节点即可。很像c++数组的首元素与数组的关系,这里我直接打印二者地址进行比较。

3.来看看插入元素

#这里的head其实可以理解为链表的head指向了链表的最后一个节点应该指向的None.所以说现在是个空链表。
head = None
for i in range(1,6):
#把之前的head作为当前元素的next。之后head不断指向新添加的元素
    head = ListNode(i,head)
insert_number = 20#想要插入的元素
head = ListNode(insert_number,head)#head指向表头(20)
while head:#只要head不为空,(因为最后一个元素的next是为空的。所以可以这样判断)
    print(head.val)
    head = head.next

输出结果:

20
5
4
3
2
1

二、Python解法

代码:

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

class Solution:
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        #初始化一个节点,temp与head都指向该节点,但是temp需要不断扩展,因为明显结果不是一个节点能完成的。然后head.next就是我们要返回的头结点地址了。因为head本身是存储的0,它的next才是我们想要的第一个有用的数所在的地方。
        temp = ListNode(0)
        head = temp
        #sum是l1,l2对应位相加的和,例如2+3=5。那么temp就存5。也可能是7+8=15,那么sum%10的数,即余数就是temp。商为1,被sum保存进入下一次循环,也就是下一位相加,例如下一位原来是3+4,但是这里有个进位1,就变成了3+4+1。之后不断循环即可。
        sum = 0
        #只要l1,l2或者sum有值就循环加。l1,l2=None,即说明到了链表尾部了。sum=0就说明最后一位没有进位了,合在一起是跳出来循环的条件
        while l1!=None or l2!=None or sum!=0:
        #只要l1,l2还有值,就加给sum。然后l1,l2往后走一步。
            if l1!=None:
                sum+=l1.val
                l1 = l1.next
            if l2!=None:
                sum+=l2.val
                l2 = l2.next
              #a:余数。sum:商。也可写成:sum,a=divmod(sum,10)
              # divmod() 函数把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)。
            a = sum%10
            sum = sum//10
            #就是程序开头的0节点后面就是和的第一位了
            temp.next = ListNode(a)
            #之后就开始进行ListNode(0).next.next的计算了
            temp =temp.next
            #返回ListNode(0)的下一个节点,因为那是和的第一位。
        return head.next
            

在这里插入图片描述

三、java解法

这里java解法思路与Python一模一样,不多做说明了。不过要注意java链表类的定义:

 public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }//构造方法,传参数用的
 }

好了,代码如下,如出一辙。。。几个区别:
none变成了null,//变成了/,or变成了||,java的类实例化多了一个new

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode head = new ListNode(0);
        ListNode temp = head;
        int sum = 0;
        while(l1!=null || l2!=null || sum!=0){
            if(l1!=null){
                sum+=l1.val;
                l1 =l1.next;
            }
            if(l2!=null){
                sum+=l2.val;
                l2=l2.next;
            }
            int a = sum%10;
            ListNode next_ = new ListNode(a);
            temp.next = next_;
            temp = temp.next;
            sum = sum/10;
        }
        return head.next;
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/ssswill/article/details/84927716