栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

LeetCode周年回归——两数相加

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

LeetCode周年回归——两数相加

两数相加

说来惭愧,距离上一次写力扣已经过去一年的时间,在这大四的一年里,从本科前三年的一无所知到现在初入茅庐,有所理解,虽然不堪出口,但进步确实是明显的,然对力扣其实算是荒废了,前面说起要学Java与Cpp,回想也只对Java有所了解,Cpp仍处于门外汉阶段。

不过总归在进步就好,此次回归也要不定期开始刷起来了,重在积累。前面刷的题要好好反思仔细思考记录,后面应该会快一点。

废话少说,这次就接着从第二题开始。

题:

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

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

解题思路:

思路想来挺简单的,就是直接将各对应位相加,注意进位就好。不过就是题中所给的是链表,我一时不知道什么是链表(尴尬,不知道Java学了个啥,但确实没掌握这一块)。所幸有度娘,百度之后才发现题中其实给了注释:

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

理解了一下大概是有指针的语言比较能常用的一种结构体,链表的当前节点储存了当前值,和下一个节点的指针。

Python代码:

自己上来写的时候直接理解成列表了,所以利用列表求解,并额外写了列表与链表转化的函数,效率当然不大行,最终beat了30左右的人:

class Solution:
    def addTwoNumbers(self, l1, l2):
        flag = 0 # 设置进位标志位
        list1 = self.getlist(l1)
        list2 = self.getlist(l2)
        len1, len2 = len(list1), len(list2)
        calen = min(len1, len2) # 运算长度
        resList = []
        for i in range(calen):
            resList.append(list1[i] + list2[i])
        if len1 > len2:
            resList.extend(list1[len2:])
        if len1 < len2:
            resList.extend(list2[len1:])

        for i in range(len(resList)):
            if flag == 1:
                resList[i] += 1
                flag = 0
            if resList[i] > 9:
                resList[i] = resList[i]%10
                flag = 1
            if (i == len(resList)-1) and (flag == 1): # 最后一位时仍需进位,则往后追加1
                resList.append(1)
        reslink = self.tolink(resList)
        return reslink

    def getlist(self, l): 
    	'''
    	将链表转化为列表
    	'''
        lis = []
        while l:
            lis.append(l.val) # 当前值赋给列表
            l = l.next # 指向下一个链表节点
        return lis

    def tolink(self, lis):
    	'''
    	将列表转化为链表
    	'''
        link = ListNode()
        link.next = ListNode(lis[0])
        p = link.next
        if len(lis) > 0:
            for i in lis[1:]:
                p.next = ListNode(i)
                p = p.next
        return link.next

然后是看了大佬的代码,并自己理解了一下,实际上就是直接利用链表节点直接相加进位,值得注意的是其中所谓dummy的东西,其实相当于是创造了一个虚拟的哨兵节点,这样可以将头节点转化为普通的节点,从而简化过程。此外,dummy=p=ListNode()的精髓在于指向了同一个对象的地址,那么在p循环的同时dummy保持了初始位置,因此得以方便地索引。

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        dummy = p = ListNode(None) # 创建空哨兵节点
        flag = 0

        while l1 and l2: # 当l1、l2不是空节点的时候循环
            if (l1.val+l2.val+flag) > 9: # 在上一位进位后,本位仍需进位时
                p.next = ListNode((l1.val+l2.val+flag)%10) # 需在进位后只取个位数字
                flag = 1
            else:
                p.next = ListNode(l1.val+l2.val + flag)
                flag = 0 # 进位后重置标志位
            p = p.next
            l1 = l1.next
            l2 = l2.next

        l = l1 if l1 else l2
        while l:
            if (l.val+flag) > 9:
                p.next = ListNode((l.val+flag)%10)
                flag = 1
            else:
                p.next = ListNode(l.val+flag)
                flag = 0
            p = p.next
            l = l.next
        if flag==1: # 最后一位时仍需进位
            p.next = ListNode(1)

        return dummy.next

但是发现和自己写的代码运行速度相差不大,但最高beat50左右,最后照搬了大佬的代码:

class Solution:
    def addTwoNumbers(self, l1, l2):
        dummy = p = ListNode(None) # 创建空哨兵节点
        sum = 0 # 设置求和

        while l1 or l2 or sum != 0: # l1或l2存在时,或不是两个0相加时才循环
            sum += (l1.val if l1 else 0) + (l2.val if l2 else 0) # 存在则相加,不存在加0
            p.next = ListNode(sum % 10) # 求和结果求模赋给下一个节点 
            # 移动到下一个节点
            p = p.next
            if l1: l1 = l1.next
            if l2: l2 = l2.next
            sum = sum // 10 # 求和结果取下一位

        return dummy.next

过程十分简洁,精妙在只写了一个循环,通过判断是否存在来做加法;同时通过设置求和sum变量求模整除来求得当前位和下一位数,避免了我自己方法设置的进位标志位的麻烦事。

运行速度有浮动,最高40ms快了15ms,但竟然已经beat95%了,看来python用户的确慢啊。。。

最后试用一下这段时间的java代码:

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        int carry = 0;
        ListNode sumHead = new ListNode(-1);
        ListNode sumNode = sumHead;   
        while (l1 != null || l2 != null) {
            // 求和
            int x = l1 != null ? l1.val : 0;
            int y = l2 != null ? l2.val : 0;
            int sum = x + y + carry;
            if (sum >= 10) {
                carry = 1;
                sum = sum - 10;
            } else {
                carry = 0;
            }
            sumNode.next = new ListNode(sum);
            // 三个指针后移
            l1 = l1 != null ? l1.next : null;
            l2 = l2 != null ? l2.next : null;
            sumNode = sumNode.next;
        }
        if (carry != 0) {
            sumNode.next = new ListNode(carry);
        }
        return sumHead.next;
    }
}

运行速度只要2ms。。。这也太夸张了

后面将直接在力扣上打卡,看心情同步csdn吧。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/302235.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号