数学(五) -- LC[415]&[455] 字符串相加与两数相加

1 字符串相加

1.1 题目描述

给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。

你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。

示例 1:
输入:num1 = “11”, num2 = “123”
输出:“134”

示例 2:
输入:num1 = “456”, num2 = “77”
输出:“533”

示例 3:
输入:num1 = “0”, num2 = “0”
输出:“0”

1.2 思路分析

  • 算法流程: 设定 i , j i,j ij 两指针分别指向 num1,num2 尾部,模拟人工加法;
    • 计算进位: 计算 carry = tmp // 10,代表当前位相加是否产生进位;
    • 添加当前位: 计算 tmp = n1 + n2 + carry,并将当前位 tmp % 10 添加至 res 头部;
    • 索引溢出处理: 当指针 i或j 走过数字首部后,给 n1,n2 赋值为 0,相当于给 num1,num2 中长度较短的数字前面填 0,以便后续计算。
    • 当遍历完 num1,num2 后跳出循环,并根据 carry 值决定是否在头部添加进位 1,最终返回 res 即可。



数学(五) -- LC[415]&[455] 字符串相加与两数相加_第1张图片

class Solution:
    def addStrings(self, num1: str, num2: str) -> str:
        i, j, carry = len(num1)-1, len(num2)-1, 0
        res = ''
        while i >= 0 or j >= 0:
            n1 = int(num1[i]) if i >= 0 else 0
            n2 = int(num2[j]) if j >= 0 else 0
            n = n1 + n2 + carry
            carry = n // 10
            res = str(n%10) + res
            i, j = i-1, j-1
        return '1'+res if carry else res

复杂度分析:
- 时间复杂度 O ( m a x ( M , N ) ) O(max(M,N)) O(max(M,N)):其中 M , N M,N MN 2 2 2 数字长度,按位遍历一遍数字(以较长的数字为准);
- 空间复杂度 O ( 1 ) O(1) O(1):指针与变量使用常数大小空间。

2 两数相加

2.1 题目描述

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

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

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

示例 1:
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.



数学(五) -- LC[415]&[455] 字符串相加与两数相加_第2张图片

示例 2:
输入:l1 = [0], l2 = [0]
输出:[0]

示例 3:
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

2.2 思路分析

由于输入的两个链表都是逆序存储数字的位数的,因此两个链表中同一位置的数字可以直接相加。

我们同时遍历两个链表,逐位计算它们的和,并与当前位置的进位值相加。具体而言,如果当前两个链表处相应位置的数字为 n 1 , n 2 n1,n2 n1,n2,进位值为 carry \textit{carry} carry,则它们的和为 n 1 + n 2 + carry n1+n2+\textit{carry} n1+n2+carry;其中,答案链表处相应位置的数字为 ( n 1 + n 2 + carry )   m o d   10 (n1+n2+\textit{carry}) \bmod 10 (n1+n2+carry)mod10,而新的进位值为 ⌊ n 1 + n 2 + carry 10 ⌋ \lfloor\frac{n1+n2+\textit{carry}}{10}\rfloor 10n1+n2+carry

如果两个链表的长度不同,则可以认为长度短的链表的后面有若干个 0 。

此外,如果链表遍历结束后,有 carry > 0 \textit{carry} > 0 carry>0,还需要在答案链表的后面附加一个节点,节点的值为 carry \textit{carry} carry

数学(五) -- LC[415]&[455] 字符串相加与两数相加_第3张图片
# 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: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        head = current = ListNode()
        res, newval = 0, 0          # 进位值和余数
        while res or l1 or l2:
            if l1: l1, newval = l1.next, l1.val + newval
            if l2: l2, newval = l2.next, l2.val + newval
            res, newval = divmod(newval,10)
            current.next = current = ListNode(newval)
            newval = res
        return head.next

复杂度分析

  • 时间复杂度: O ( max ⁡ ( m , n ) ) O(\max(m,n)) O(max(m,n)),其中 m m m n n n 分别为两个链表的长度。我们要遍历两个链表的全部位置,而处理每个位置只需要 O ( 1 ) O(1) O(1) 的时间。
  • 空间复杂度: O ( 1 ) O(1) O(1)。注意返回值不计入空间复杂度。

3 两数相加 II

3.1 题目描述

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

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

示例1:
输入:l1 = [7,2,4,3], l2 = [5,6,4]
输出:[7,8,0,7]



数学(五) -- LC[415]&[455] 字符串相加与两数相加_第4张图片

示例2:
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[8,0,7]

示例3:
输入:l1 = [0], l2 = [0]
输出:[0]

3.2 思路分析

  • 反转链表 l 1 l_1 l1
  • 反转链表 l 2 l_2 l2
  • 调用 2. 两数相加 的代码,得到链表 l 3 l_3 l3
  • 反转链表 l 3 l_3 l3 返回 l 3 l_3 l3 作为答案。
class Solution:
    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        def list_reverse(l):
            prev, curr = None, l
            while curr:
                temp = curr.next
                curr.next = prev
                prev = curr
                curr = temp
            return prev


        def two_numbers(l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
            head = current = ListNode()
            res, newval = 0, 0          # 进位值和余数
            while res or l1 or l2:
                if l1: l1, newval = l1.next, l1.val + newval
                if l2: l2, newval = l2.next, l2.val + newval
                res, newval = divmod(newval,10)
                # current.next = current = ListNode(newval)
                current.next = current = ListNode(newval)
                newval = res
            return head.next

        dummy = ListNode(-1)
        l1, l2 = list_reverse(l1), list_reverse(l2)
        return list_reverse(two_numbers(l1, l2))

你可能感兴趣的:(LC,and,PAT,leetcode,字符串,数组,链表)