1-两数相加 leetcode2

文字比较多,但是耐下心来,看完绝对能懂。(我也是上课,做的笔记,整理归纳,再加上我的理解,总结的)

1. 题目

  • 两个非空链表用来 表示两个非负整数

  • 各自的位数是按照逆序的方式存储, 并且 每个节点只能存储一位数字

  • 如果我们将这两个数相加起来, 返回一个新的链表, 并且表示它们的和 (逆序)

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

    在这里插入图片描述

2. 链表(⭐)

这道题的前置知识,链表,必须了解

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

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

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

  • 单向链表的代码实现(Java):

    public class ListNode {
        int val;    // 数据域
        ListNode next;// 指针域(下一个节点的地址值)
    
        public ListNode() {
        } // 无参构造
        public ListNode(int val) {
            this.val = val;
        } // 有参构造
    }
    
    • 注意

      • 代码中的数据域,类型为 int, 那是因为在这个算法体中,存储的是int类型。

      • 在实际开发中,ListNode应该使用泛型

        public class ListNode<T> {
            T val;
            ListNode<T> next;
            public ListNode() {
            }// 无参构造
            public ListNode(T val) {
                this.val = val;
            }// 有参构造
            public ListNode(T val, ListNode<T> next) {
                this.val = val;
                this.next = next;
            }// 全参构造
        }
        
  • 特点:

    1. 链表的数据存储,不要求连续空间,不限制容量,可在运行时动态生成

      • 注:数组的存储空间,是一块儿连续的内存。且数组一旦创建,就固定了大小
    2. 数据的逻辑顺序通过指针链接次序实现

    3. 从链表的头节点,依次访问后面的节点(即单向链表)

      • 双向链表,可以从尾节点,依次向前面的节点访问
      • 双向链表,有两个指针域,一个指向前节点,一个指向后节点
    4. 在链表表头插入数据的时间复杂度是O(1)

      • 在头结点前插入数据,只需要将节点的指向头结点,这么一个操作。所以时间复杂度为 O(1)

3. 解题思路

  • 解法1 :分别将链表转换成数字,再相加,在将结果转换为 链表

  • 解法2 :链表一一对应,将链表对应位置的数字相加

3.1 暴力解法

即解法1,因为最直接,所以往往这总方式被称为暴力解法

  • 步骤:

    1. 遍历链表,通过数学的思维(除or取模),将每一个节点的数字,拼凑成整数

      • 除: 101/10=10 ,取商
      • 取模: 101%10=1 ,取余数
    2. 对两个整数进行求和得到结果:sum

    3. 将 sum 按照数学思维 再转成链表

      在这里插入图片描述

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

    • 边界问题:

      • 链表什么时候指向尾节点呢?

        • 尾节点作为循环结束的标志:next == null
      • 整数,在转化为链表时,什么时候结束?

        • 整数值value = 0 时,结束
    • 细节问题:

      • 链表存储为逆序,最高位其实是最后一个节点。
      • 题目没有给出整数的范围:
        • 题目中表示,链表的一个节点只存储一个数字,不会发生越界问题。
        • 但是,这一条链表所表示的数值可以非常大,可能会超出数据类型的范围。
          • Java提供了 BigInteger 、BigDecimal 等等,大数类型,来替代基本数据类型
        • 若 int 溢出可以用long,long 溢出?
          • 所以,当链表所表示的数值,溢出时。暴力解法,将不可使用
  • 代码实现:

    1. 链表转换为整数

      public static long listToNumber(ListNode node) {
              long nodeOfValue = 0; // 初始化,节点所代表的整数值
              int n = 0;  // 位数,多少个0:0代表个位, 1代表十位, 以此类推
              while (node != null) {  // 判断是否为 尾节点
                  int pow = (int) Math.pow(10, n); //10的n次方,代表位数:1,10,100,...
                  nodeOfValue += (long) node.val * pow; // 累加, 最终得到整个链表所表示的值
                  n++;
                  node = node.next;// 将当前节点后移,得到下一个节点
              }
              return nodeOfValue;
          }
      
    2. 整数转换为链表

      public static ListNode numberToList(long sum) {
          // 初始化一个新链表
          ListNode headNode = new ListNode();// 头结点
          ListNode curNode = headNode;// 当前节点
          if (sum == 0) { // 边界判断
              headNode = new ListNode(0);
              return headNode;
          }
          // 数字转成链表
          while (sum > 0) {
              int val = (int) (sum % 10); // 每次取当前最低位
              curNode.next = new ListNode(val);  //插⼊入链表尾部
              sum = sum / 10; // 移除最低位
              curNode = curNode.next; //链表尾部指针移动
          }
          return headNode.next;
      }
      
      • 注意
        1. 头结点,就代表整个链表。所以,返回值一般返回:headNode.next
        2. 操作链表时,一般会创建 HeadNodeCurrnetNode
          • 创建头结点:HeadNode,是用来指向该链表的起始位置,很重要。不然该链表就会丢失
          • 创建当前节点:CurrnetNode,用来对链表进行操作
          • 头结点和当前节点,最开始指向的是同一个节点。第一次对当前节点操作,实际上就是对头结点操作。
    3. 核心代码:

      public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
          // 得到两个链表所代表的整数
          long value1 = listToNumber(l1);
          long value2 = listToNumber(l2);
          //数字相加
          long sum = value1 + value2;
          // 得到结果
          return numberToList(sum);
      }
      

3.3 数学思维解法

链表一一对应,将链表对应位置的数字相加

  • 步骤:

    1. 遍历链表

      • 和暴力解法不同的是,不是单个链表的遍历,而是同时遍历。
      • 如果两个链表长度不一致的情况呢?以长的为准
    2. 对应节点的数值,进行相加

    3. 每个对应节点,相加的结果,直接插入到新链表的尾部

      • 如果结果大于10,那么进位,加到下一个节点

        在这里插入图片描述

  • 边界和细节问题:

    1. 边界问题:

      • 链表的边界条件:链表结尾时,next == null
    2. 细节问题:

      • 两个链表长度不一致,短的链表高位视为 0
      • 链表的高位发生进位,那么结果需要链表增加一个节点存放进位的数
  • 代码:

    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode resHeadNode = new ListNode();// 实例化了结果链表的头结点
        ListNode curNode = resHeadNode;// 结果链表的遍历指针
        int carryDigit = 0; // 进位数
    
        // 1. 遍历两个链表
        while (l1 != null || l2 != null) { // 不等于null,表示还有节点可以遍历
            // 获取当前节点的值,若没有则取0
            int x = l1 != null ? l1.val : 0;
            int y = l2 != null ? l2.val : 0;
    
            // 2. 取到值后,对应节点位相加, 还要加上进位数
            int sum = x + y + carryDigit;
            // 对求和结果进行 进位处理
            carryDigit = sum / 10; // 得到进位数,若没有则为0
            int num = sum % 10; // 得到节点中的数值
    
            // 3. 得到相加的结果,将其插入新链表的尾部
            curNode.next = new ListNode(num);
            curNode = curNode.next; // 指针后移,指向新插入的节点
    
            // 4. 相加的两条链表的指针也要后移
            l1 = (l1 == null) ? l1 : l1.next;
            l2 = (l2 == null) ? l2 : l2.next;
        }
        // 5. 遍历结束后,判断 carryDigit 看是否发生进位
        if (carryDigit>0){
            curNode.next = new ListNode(carryDigit);
        }
        return resHeadNode.next;
    }
    

    总结步骤:

    1. 同时遍历两个链表 —— 构建结果链表
      • 在循环中,首先取到当前节点的值
      • 对应节点的两值相加,还要加上进位数,得到结果sum
      • 对sum,进行进位数处理,得到新的进位数、待插入链表的值num
      • 将num实例化为节点,并且插入到新链表的尾部
      • 新链表的操作节点后移,指向插入到链表
      • 相加的两条链表的指针也要后移,指向下一个 要相加的节点
      • 依次循环,等待结束
    2. 遍历结束后,构建链表成功。但是,还要判断,进位数是否大于 0, 若大于0 那么就要发生进位
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
根据提供的引用内容,Leetcode 2 "两数相加"是一个涉及链表的问题。该问题给定了两个非负整数,每个整数的每一位都是按照逆序的方式存储在链表中。我们需要将这两个链表相加,并返回一个新的链表作为结果。 具体解题思路可以使用迭代法或递归法来解决。迭代法的伪代码如下所示: ``` 初始化一个哑节点 dummy 和一个进位 carry,同时把两个链表的头节点分别赋值给 p 和 q 遍历链表,直到 p 和 q 都为 None 计算当前的和 sum 为 p.val + q.val + carry 计算当前的进位 carry 为 sum // 10 创建一个新节点 node,节点的值为 sum % 10 把新节点连接到结果链表的尾部 更新 p 和 q 分别为 p.next 和 q.next 如果最后还有进位 carry,则创建一个新节点 node,节点的值为 carry,并连接到结果链表的尾部 返回结果链表的头节点 dummy.next ``` 递归法的伪代码如下所示: ``` 定义一个辅助函数 addTwoNumbersHelper,输入为两个链表的头节点 p 和 q,以及进位 carry 如果 p 和 q 都为 None 且 进位 carry 为 0,则返回 None 计算当前的和 sum 为 p.val + q.val + carry 计算当前的进位 carry 为 sum // 10 创建一个新节点 node,节点的值为 sum % 10 设置新节点的下一个节点为递归调用 addTwoNumbersHelper(p.next, q.next, carry) 返回新节点 返回 addTwoNumbersHelper(p, q, 0) 的结果 以上是解决 Leetcode 2 "两数相加"问题的两种方法。如果你还有其他相关问题,请
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

疯子的模样

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

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

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

打赏作者

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

抵扣说明:

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

余额充值