【算法训练-链表 五】【链表求和】:链表相加(逆序)、链表相加II(顺序)

简介: 【算法训练-链表 五】【链表求和】:链表相加(逆序)、链表相加II(顺序)

废话不多说,喊一句号子鼓励自己:程序员永不失业,程序员走向架构!本篇Blog的主题是【链表相加】,使用【链表】这个基本的数据结构来实现,这个高频题的站点是:CodeTop,筛选条件为:目标公司+最近一年+出现频率排序,由高到低的去牛客TOP101去找,只有两个地方都出现过才做这道题(CodeTop本身汇聚了LeetCode的来源),确保刷的题都是高频要面试考的题。

名曲目标题后,附上题目链接,后期可以依据解题思路反复快速练习,题目按照题干的基本数据结构分类,且每个分类的第一篇必定是对基础数据结构的介绍

链表相加【MID】

题干

首先来一道逆序版,稍微比较好搞一些的,因为链表只能向后遍历:

解题思路

整体思路就是遍历完两个链表进行相加并将结果集放到新的链表上

  1. 设置返回链表的链表头,设置进位cnt=0.
  2. 从头开始遍历两个链表,直到两个链表节点都为空:
  1. 每次取出不为空的链表节点值,为空就设置为0
  2. 将两个数字与cnt相加,就是当前的总和
  3. 将总和(对10取模)加入新的链表节点,连接在返回链表后面,并继续往后遍历,并用总和对10除获取进位值
  1. 如果两个链表都遍历完成,cnt进位还有值,则补充创建一个节点,值为cnt

代码实现

给出代码实现基本档案

基本数据结构链表

辅助数据结构

算法迭代

技巧双指针

其中数据结构、算法和技巧分别来自:

  • 10 个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie 树
  • 10 个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法
  • 技巧:双指针、滑动窗口、中心扩散

当然包括但不限于以上

;
import java.util.*;
/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 *   public ListNode(int val) {
 *     this.val = val;
 *   }
 * }
 */
public class Solution {
    /**
    * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
    *
    *
    * @param head1 ListNode类
    * @param head2 ListNode类
    * @return ListNode类
    */
    public ListNode addInList (ListNode head1, ListNode head2) {
        // 1 先将两个链表反转过来
        ListNode p1 = head1;
        ListNode p2 = head2;
        // 2 设置结果集以及初始化进位标识符
        ListNode dummy = new ListNode(-1);
        ListNode p = dummy;
        int cnt = 0;
        // 3 目标是遍历完两个链表的全部长度
        while (p1 != null || p2 != null) {
            // 3-1 获取当前节点值,如果是null节点则值为0
            int d1 = p1 == null ? 0 : p1.val;
            int d2 = p2 == null ? 0 : p2.val;
            // 3-2 计算总和、进位值、当前节点值
            int curSum = d1 + d2 + cnt;
            cnt = curSum / 10;
            p.next =  new ListNode(curSum % 10);
            // 3-3 结果指针移动,节点指针移动
            p = p.next;
            p1 = p1 == null ? null : p1.next;
            p2 = p2 == null ? null : p2.next;
        }
        // 4 全部结果如果遍历完,进位值还是大于0,则设置为最后一个节点
        if (cnt > 0) {
            p.next =  new ListNode(cnt);
        }
        return dummy.next;
    }
}

复杂度分析

时间复杂度:遍历链表,时间复杂度为O(N)

空间复杂度:不算返回的结果集的话,没有用到辅助空间,所以空间复杂度为O(1)

链表相加II【MID】

题干

进阶版,值为顺序,但链表是单向的,不能反过来遍历

解题思路

虽然链表不能反过来遍历,但是我们可以开始的时候就反转链表,然后返回结果时候再反转回去

  1. 任意一个链表为空,返回另一个链表就行了,因为链表为空相当于0,0加任何数为0,包括另一个加数为0的情况。
  2. 相继反转两个待相加的链表,反转过程可以参考反转链表。
  3. 设置返回链表的链表头,设置进位cnt=0.
  4. 从头开始遍历两个链表,直到两个链表节点都为空:
  1. 每次取出不为空的链表节点值,为空就设置为0
  2. 将两个数字与cnt相加,就是当前的总和
  3. 将总和(对10取模)加入新的链表节点,连接在返回链表后面,并继续往后遍历,并用总和对10除获取进位值
  1. 如果两个链表都遍历完成,cnt进位还有值,则补充创建一个节点,值为cnt
  2. 返回前将结果链表再反转回来。

代码实现

给出代码实现基本档案

基本数据结构链表

辅助数据结构

算法迭代

技巧双指针

其中数据结构、算法和技巧分别来自:

  • 10 个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie 树
  • 10 个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法
  • 技巧:双指针、滑动窗口、中心扩散

当然包括但不限于以上

;
import java.util.*;
/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 *   public ListNode(int val) {
 *     this.val = val;
 *   }
 * }
 */
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param head1 ListNode类
     * @param head2 ListNode类
     * @return ListNode类
     */
    public ListNode addInList (ListNode head1, ListNode head2) {
        // 1 先将两个链表反转过来
        ListNode p1 = reverse(head1);
        ListNode p2 = reverse(head2);
        // 2 设置结果集以及初始化进位标识符
        ListNode dummy = new ListNode(-1);
        ListNode p = dummy;
        int cnt = 0;
        // 3 目标是遍历完两个链表的全部长度
        while (p1 != null || p2 != null) {
            // 3-1 获取当前节点值,如果是null节点则值为0
            int d1 = p1 == null ? 0 : p1.val;
            int d2 = p2 == null ? 0 : p2.val;
            // 3-2 计算总和、进位值、当前节点值
            int curSum = d1 + d2 + cnt;
            cnt = curSum / 10;
            p.next =  new ListNode(curSum % 10);
            // 3-3 结果指针移动,节点指针移动
            p = p.next;
            p1 = p1 == null ? null : p1.next;
            p2 = p2 == null ? null : p2.next;
        }
        // 4 全部结果如果遍历完,进位值还是大于0,则设置为最后一个节点
        if (cnt > 0) {
            p.next =  new ListNode(cnt);
        }
        return reverse(dummy.next);
    }
    private ListNode reverse(ListNode head) {
        if (head == null) return null;
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
            ListNode pNext = cur.next;
            cur.next = pre;
            pre = cur;
            cur = pNext;
        }
        return pre;
    }
}

复杂度分析

时间复杂度:遍历链表,时间复杂度为O(N)

空间复杂度:不算返回的结果集的话,没有用到辅助空间,所以空间复杂度为O(1)

相关文章
|
1月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
91 29
|
1月前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
103 25
|
4月前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
4月前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
4月前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
5月前
|
存储 缓存 算法
经典算法之链表篇(三)
经典算法之链表篇(三)
113 4
|
5月前
|
算法
经典算法之链表篇(二)
经典算法之链表篇(二)
|
2天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于生物地理算法的MLP多层感知机优化matlab仿真
本程序基于生物地理算法(BBO)优化MLP多层感知机,通过MATLAB2022A实现随机数据点的趋势预测,并输出优化收敛曲线。BBO模拟物种在地理空间上的迁移、竞争与适应过程,以优化MLP的权重和偏置参数,提升预测性能。完整程序无水印,适用于机器学习和数据预测任务。
|
1天前
|
资源调度 算法 数据可视化
基于IEKF迭代扩展卡尔曼滤波算法的数据跟踪matlab仿真,对比EKF和UKF
本项目基于MATLAB2022A实现IEKF迭代扩展卡尔曼滤波算法的数据跟踪仿真,对比EKF和UKF的性能。通过仿真输出误差收敛曲线和误差协方差收敛曲线,展示三种滤波器的精度差异。核心程序包括数据处理、误差计算及可视化展示。IEKF通过多次迭代线性化过程,增强非线性处理能力;UKF避免线性化,使用sigma点直接处理非线性问题;EKF则通过一次线性化简化处理。
|
3天前
|
算法 数据安全/隐私保护
基于二次规划优化的OFDM系统PAPR抑制算法的matlab仿真
本程序基于二次规划优化的OFDM系统PAPR抑制算法,旨在降低OFDM信号的高峰均功率比(PAPR),以减少射频放大器的非线性失真并提高电源效率。通过MATLAB2022A仿真验证,核心算法通过对原始OFDM信号进行预编码,最小化最大瞬时功率,同时约束信号重构误差,确保数据完整性。完整程序运行后无水印,展示优化后的PAPR性能提升效果。