02两数相加.2

02两数相加.2

题目描述

给出两个非空链表用来表示两个非负整数
其中它们各自的位数是按照逆序的方式存储的,并且它们的每个节点只能存储一位数字
如果我们将这两个数相加起来,则会返回一个新的链表来表示它们的和
您可以假设除了数字0之外,这两个数都不会以0开头
在这里插入图片描述

1. Comprehend 理解题意

理解题意

  • 一个链表表示一个整数
  • 每个节点存储一个数字
  • 各自的位数逆序存储
  • 链表相加,即链表表示的整数相加
  • 返回链表表示的两数之和

在这里插入图片描述

细节问题:

  • 两个链表都是非空的
  • 两个非负整数
  • 两个数字都不会以0开头
  • 数字逆序排列,第一个节点表示整数的最低位
  • 【重点】题目没有明确整数的范围,这是个容易忽略的点

解题思路

解法—:分别将链表转成数字,再相加
解法二:直接将对应位置数字相加

2.Choose 数据结构及算法思维选择

链表

  • 一种物理存储上非连续、非顺序的存储结构

  • 由一系列节点组成,可以在运行时动态生成

  • 每个结点包括两个部分:数据域;指针域

链表的特点

  • 数据存储不要求连续空间,不限制容量
  • 数据的逻辑顺序通过指针链接次序实现
  • 从链表头部依次访问后面的节点
  • 在链表表头插入数据的时间复杂度是O(1)
class ListNode {
    int val;
    ListNode next;
    ListNode() {};
    ListNode(int x) {
		val = x; 
     }
}

在这里插入图片描述

数据结构的选择

链表

算法思维的选择

解法一:分别将链表转成数字,再相加
遍历
解法二:直接将对应位置数字相加
数学

3.Code 基本解法及编码实现

解法一:暴力解法

在这里插入图片描述

  1. 遍历两个链表使用数学思维分别将他们转成整数
  2. 对两个整数进行求和得到sum
  3. 将sum按照数学思维再转成链表

解法一:暴力解法边界和细节问题

边界问题

  • 链表转整数时,next==null结尾
  • 整数转链表,处理完最高位:value==0

细节问题

  • 不同节点代表不同的位数
  • 题目没有明确整数范围:

​ int 溢出可以用 long,long 溢出?

三. Code 基本解法及编码实现

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        long number1 = 0;
        int digit = 0;
        //将链表转成数
        while (l1 != null) {
            int value = l1.val;
            number1 = number1 + (int) (value * Math.pow(10, digit));
            l1 = l1.next;
            digit++;
        }
        long number2 = 0;
        digit = 0;
        //将链表转成数
        while (l2 != null) {
            int value = l2.val;
            number2 = number2 + (int) (value * Math.pow(10, digit));
            l2 = l2.next;
            digit++;
        }
        //求和
        long sum = number1 + number2;
        ListNode resultHead = new ListNode(-1);
        ListNode currentNode = resultHead;
        //如果等于0,则构造List(0)
        if (sum == 0) {
            currentNode.next = new ListNode(0);
        }
        while (sum != 0) {
            int val = (int) (sum % 10);
            sum = sum / 10;
            currentNode.next = new ListNode(val);
            currentNode = currentNode.next;
        }
        return resultHead.next;
    }
}

时间复杂度与空间复杂度

时间复杂度

  • 分别遍历两个链表:O(m + n)

  • 将两数字的和转成链表,在链表尾部插入节点:

    O(k)=O(max(m, n))

    PS: k=max(m, n)或 k=max(m, n)+1

  • 总复杂度:O(m+n+max(m,n)) 近似于O(m+n)

空间复杂度

  • 创建一个新链表,其长度取决于两数之和的位数:O(max(m, n))

4.Consider 思考更优解

  1. 剔除无效代码或优化空间消耗
    • 减少循环层级和次数
    • 优化代码
  2. 寻找更好的算法思维
    • 能否跳过链表转整数的过程?
    • 可否直接将链表对应位置数字相加?
    • 借鉴其它算法

5.Code 最优解思路及编码实现

最优解:数学思维解法

  1. 遍历两个链表
  2. 对应位置的节点数值相加
  3. 将结果插入新链表尾部 大于10,则进位,将进位加到下个节点

在这里插入图片描述

最优解:边界和细节问题

边界问题

  • 两个链表边界:next==null

细节问题

  • 两个链表长度不一致,短链表高位视为0
  • 链表最高位发生进位,结果链表需要增加一 个节点存放进位数字

Code 最优解思路及编码实现

class Solution {
      public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
          ListNode resultHead = new ListNode(-1);
          ListNode currentNode = resultHead;
          ListNode number01 = l1;
          ListNode number02 = l2;
          int carry = 0;
          while (number01 != null || number02 != null) {
              //如果当前为尾节点,则为0
              int num1 = number01 != null ? number01.val : 0;
              int num2 = number02 != null ? number02.val : 0;
              int sum = num1 + num2 + carry;
              //得到进位
              carry = sum / 10;
              //得到当前位
              sum = sum % 10;
              //创建新节点,
              currentNode.next = new ListNode(sum);
              currentNode = currentNode.next;
              //如果当前指针为null,则不移动,指针不为null,则移动到下一个节点
              number01 = number01 != null ? number01.next : number01;
              number02 = number02 != null ? number02.next : number02;
          }
          //如果有进位
          if (carry > 0) {
              currentNode.next = new ListNode(carry);
          }
          return resultHead.next;
      }
  }

时间复杂度及空间复杂度

时间复杂度:O(max(m,n))

  • 两个链表的加法运算: O(max(m,n))
  • 与暴力解法的O(m+n)差别不大, 但大数运算以及循环次数来看, 更优

空间复杂度:O(max(m,n))

  • 创建需要创建一个新链表: O(max(m, n))

6.Change 变形延伸

  • 6C解题法
  • 链表的特点
    • 数据存储不要求连续空间,不限制容量
    • 数据的逻辑顺序通过指针链接次序实现
    • 从链表头部依次访问后面的节点
    • 在链表表头插入数据的时间复杂度是O(1)
  • 数学思维
    • 数学竖式
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pirmingham

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值