LeetCoed 2, 23, 25, 112, 113

news2024/12/22 20:30:19

文章目录

  • 1. 两数相加
  • 2. K 个一组翻转链表
  • 3. 合并 K 个升序链表
  • 4. 路径总和I
  • 5. 路径总和II

1. 两数相加

题目详情见: LeetCode2. 两数相加

题目描述相对来说比较绕, 我们可以直接理解为两个多位的整数相加, 只不过整数的每一位都是通过链表进行存储; 比如, 整数 342, 通过链表存储正常来说应该是 3->4->2, 但是计算时, 往往需要从低位开始计算, 逢十进一, 所以题目中直接将整数表示为 2->4->3, 这样反而不用将链表顺序进行反转了, 直接相加就可以了.

img

需要注意的是如果两个链表的长度不同, 则可以认为长度短的链表的后面有若干个 0, 链表遍历结束, 则如果进位值大于0, 则还需要在结果链表中附加一个值为1的节点.

因为链表是逆序的, 因此直接对应数字相加即可; 基本操作是遍历两个链表, 逐位计算它们的和, 并与当前位置的进位值相加.

比如, 两个链表对应位的数字分别为 n1n2, 进位为 carry (初始值为0, 有 0 和 1 两种取值), 则它们的和为 n1 + n2 + carry, 对应位上数字变为 (n1 + n2 + carry) % 10, 新的进位为(n1 + n2 + carry) / 10.

如果两个链表长度不一样, 长度短的链表后续对应位上值均为0即可; 如果遍历结束之后, carray大于0 (也就是等于1), 则在结构链表后面新增一个节点.

代码实现如下:

class Solution {
    // 计算链表长度
    public static int listLength(ListNode head) {
        int len = 0;
        while (head != null) {
            len++;
            head = head.next;
        }
        return len;
    }
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode cur1 = l1;
        ListNode cur2 = l2;
        // 让cur1指向较长的链表
        int len1 = listLength(cur1);
        int len2 = listLength(cur2);
        if (len1 < len2) {
            cur1 = l2;
            cur2 = l1;
        }
        ListNode retHead = cur1;

        int carry = 0; // 记录进位
        int curNum = 0;

        // 记录长链表遍历到哪里了
        // 方便遍历完两个链表之后如果还有进位, 就new一个新的节点方便尾插到链表中.
        ListNode last = cur1;

        // 首先遍历至较短链表为null
        while (cur2 != null) {
            curNum = cur1.val + cur2.val + carry;
            cur1.val = curNum % 10;
            carry = curNum / 10;
            last = cur1;
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        // 继续接着上面的位置遍历长链表
        while (cur1 != null) {
            curNum = cur1.val + carry;
            cur1.val = curNum % 10;
            carry = curNum / 10;
            last = cur1;
            cur1 = cur1.next;
        }
        if (carry != 0) {
            last.next = new ListNode(1);
        }
        return retHead;
    }
}

2. K 个一组翻转链表

题目详情见: LeetCode25. K 个一组翻转链表

本题需要设计两个方法:

第一个方法ListNode getKGroupEnd(ListNode startNode, int k): 从链表 startNode 位置开始是第 1 个节点, 数够 k 个节点,返回第 k 个节点.

比如链表为:

...-> startNode -> b -> c -> d -> e
k = 3

表示从 start 开始, 数够 3 个, 所以返回 c 节点

如果是下述情况

...-> start -> b -> c -> null
k = 6

由于 start 后面不够 6 个, 所以返回 null.

// 找到每组内要逆序的尾节点返回
private static ListNode getKGroupEnd(ListNode startNode, int k) {
    while (--k != 0 && startNode != null) {
        startNode = startNode.next;
    }
    return startNode;
}

第二个方法void reverse(ListNode startNode, ListNode endNode), 表示反转 startNode 到 endNode 之间的链表.

例如: 原链表为

....->a->b->c->d->e....

假设 startNode = a, endNode = d, 经过reverse方法, 会变成

...d->c->b->a->e.....

reverse 方法也相对比较简单, 实现代码如下:

 public static void reverse(ListNode start, ListNode end) {
    end = end.next;
    ListNode pre = null;
    ListNode cur = start;
    while (cur != end) {
        ListNode tmp = cur.next;
        cur.next = pre;
        pre = cur;
        cur = tmp;
    }
    start.next = end;
}

有了上述两个方法, 我们可以比较方便实现原题要求, 主流程如下:

  1. 首先要先将第一组进行反转.
  2. 每次的反转如果节点个数小于 k 了, 就直接返回.
  3. 每次组内反转之后的组内尾节点就是 startNode 了, 用 lastEndNode 记录下来.
  4. 每次反转之后要记得和前一个组的尾节点连接, 即和 lastEndNode 连接.
  5. 只要 lastEndNode 的下一个节点不为 null, 就还可以继续分组反转.

完整代码如下:

class Solution {
    // 找到每组内要逆序的尾节点返回
    private static ListNode getKGroupEnd(ListNode startNode, int k) {
        while (--k != 0 && startNode != null) {
            startNode = startNode.next;
        }
        return startNode;
    }
    private static void reverse(ListNode startNode, ListNode endNode) {
        endNode = endNode.next;
        ListNode cur = startNode;
        ListNode prev = null;
        ListNode curNext = null;
        while (cur != endNode) {
            curNext = cur.next;
            cur.next = prev;
            prev = cur;
            cur = curNext;
        }
        startNode.next = endNode;
    }
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode startNode = head;
        // 先将第一组进行反转
        ListNode endNode = getKGroupEnd(startNode, k);
        // 链表中节点个数小于k, 直接返回
        if (endNode == null) {
            return head;
        }
        // 第一次进行反转后的endNode节点就是最终要返回的头节点了
        head = endNode;
        // 反转
        reverse(startNode, endNode);
        // 拿到第一组反转后的组内尾节点
        ListNode lastEndNode = startNode;
        while (lastEndNode.next != null) {
            startNode = lastEndNode.next;
            endNode = getKGroupEnd(startNode, k);
            if (endNode == null) {
                return head;
            }
            reverse(startNode, endNode);
            // 与前面的内容进行连接
            lastEndNode.next = endNode;
            lastEndNode = startNode;
        }
        return head;
    }
}

3. 合并 K 个升序链表

题目详情见: LeetCode23. 合并 K 个升序链表

思路如下:

准备一个小根堆, 并把每个链表的头节点加入到小根堆中, 此时, 小根堆堆顶弹出的节点一定是最后生成新链表的头节点.

假设链表为: L1,L2…LN

  • 第一步, 先将 L1,L2…LN 的头节点 L1H,L2H…LNH 加入小根堆;
  • 第二步, 从小根堆堆顶弹出一个元素, 作为最后链表的头节点;
  • 第三步, 第二步中弹出节点所在的链表, 假设是 i 号链表, 那么就找弹出节点的下一个节点 (不为 null) 再入堆;
  • 第四步, 循环, 只要堆不为空就弹出堆顶节点添加到新链表中, 只要堆顶节点的下一个节点不为 null 就将这个节点再入堆.

这样就能保证每次添加的新链表节点是所有链表节点中最小的那一个.

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null) {
            return null;
        }
        PriorityQueue<ListNode> heap = new PriorityQueue<ListNode>(new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                return o1.val - o2.val;
            }
        });
        for (int i = 0; i < lists.length; i++) {
            if (lists[i] != null) {
                heap.offer(lists[i]);
            }
        }
        if (heap.isEmpty()) {
            return null;
        }
        ListNode head = heap.poll();
        ListNode tail = head;
        if (tail.next != null) {
            heap.offer(tail.next);
        }
        while (!heap.isEmpty()) {
            ListNode cur = heap.poll();
            tail.next = cur;
            tail = cur;
            if (cur.next != null) {
                heap.offer(cur.next);
            }
        }
        return head;
    }
}

4. 路径总和I

题目详情见: 112. 路径总和

使用递归, 先从根结点搜索一条路径到底, 不符合条件后便后退一步, 然后继续进行搜索.

class Solution112 {
    /*// 方法一
    // 一直想向下递归, 每次sum减去当前节点的值
    // 碰到叶子节点后判断叶子节点中的值和剩下的值是否相同
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (root == null) {
            return false;
        }
        return process(root, targetSum);
    }
    public static boolean process(TreeNode childRoot, int subSum) {
        if (childRoot.left == null && childRoot.right == null) {
            return childRoot.val == subSum;
        }

        boolean ans = childRoot.left != null ? process(childRoot.left, subSum - childRoot.val) : false;
        ans |= childRoot.right != null ? process(childRoot.right, subSum - childRoot.val) : false;

        return ans;
    }*/

    // 方法二
    // 向下递归的过程累加节点值
    // 到叶子节点后判断和目标值是否相同
    public static boolean isSum;
    public static boolean hasPathSum(TreeNode root, int targetSum) {
        if (root == null) {
            return false;
        }
        isSum = false;
        process(root, 0, targetSum);
        return isSum;
    }
    public static void process(TreeNode childRoot, int preSum, int sum) {
        if (childRoot.left == null && childRoot.right == null) {
            if (childRoot.val + preSum == sum) {
                isSum = true;
            }
            return ;
        }

        // childRoot是非叶子节点
        preSum += childRoot.val;
        if (childRoot.left != null) {
            process(childRoot.left, preSum, sum);
        }
        if (childRoot.right != null) {
            process(childRoot.right, preSum, sum);
        }
    }
}

5. 路径总和II

题目详情见: 113. 路径总和 II

与上一题不同, 这个题需要我们找出所有路径之和等于目标值的具体路径; 所以我们在搜索的过程中需要使用一个顺序表来记录当前的路径, 当该条路径符合题意时将其存入最后返回的顺序表中即可; 这个题特别需要注意的是搜索路径在回退时一定要注意将当前节点从路径中删除.

class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> ans = new ArrayList<>();
        if (root == null) {
            return ans;
        }
        ArrayList<Integer> path = new ArrayList<>();
        process(root, path, 0, targetSum, ans);
        return ans;
    }
    public static void process(TreeNode root, List<Integer> path, int preSum,
                               int sum, List<List<Integer>> ans) {
        // 叶子节点
        if (root.left == null && root.right == null) {
            if (preSum + root.val == sum) {
                path.add(root.val);
                ans.add(new ArrayList<>(path));
                // 将当前节点从路径中删除
                path.remove(path.size() - 1);
            }
            return;
        }
        // 非叶子节点
        path.add(root.val);
        preSum += root.val;
        if (root.left != null) {
            process(root.left, path, preSum, sum, ans);
        }
        if (root.right != null) {
            process(root.right, path, preSum, sum, ans);
        }
        path.remove(path.size() - 1);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/494082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用Webpack搭建项目(vue篇)

本篇承接使用Webpack搭建项目&#xff08;react篇&#xff09; 由于大部分配置一样&#xff0c;我们从上一篇react项目中&#xff0c;复制webpack.dev.js以及webpack.prod.js 开发模式 1.删除ReactRefreshWebpackPlugin 2.自动补充拓展名修改为.vue文件&#xff0c;同时处理…

每天一道算法练习题--Day21 第一章 --算法专题 --- ----------位运算

我这里总结了几道位运算的题目分享给大家&#xff0c;分别是 136 和 137&#xff0c; 260 和 645&#xff0c; 总共加起来四道题。 四道题全部都是位运算的套路&#xff0c;如果你想练习位运算的话&#xff0c;不要错过哦&#xff5e;&#xff5e; 前菜 开始之前我们先了解下…

【linux的学习与软件安装】

文章目录 linux的学习一、工具安装与联网&#xff1f;二、Linux软件安装1.安装jdk2.安装MySQL安装redis linux的学习 一、工具安装与联网&#xff1f; 1.1安装好VM后 进入vi /etc/sysconfig/network-scripts/ifcfg-ens33 然后ip addr 查看ip 1.2打开IDEA的tools 二、Linux软…

网络编程 | 多进程多线程并发服务器代码实现

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

5.5 Mybatis Update标签实战,返回值是什么? 教你通常处理做法

本文目录 前言一、update标签实战① 在UserMapper接口中新增update方法② MybatisX插件生成update标签③ 写update SQL 语句 二、update sql返回值是什么?三、Mybatis update标签返回值是什么?四、实现简易的修改密码API1. dal层2. service层3. web层自测通过 五、Git提交最后…

vue - 常见的移动端rem适配方案

移动端rem适配方案 rem适配原理方案1&#xff1a;rem媒体查询方案2&#xff1a;jsrem方案3&#xff1a;vwrem&#xff08;不用查询屏幕宽度&#xff09; 移动端适配经常使用的就是 rem; 主要有以下几种方案&#xff1a; 1&#xff1a;rem 媒体查询&#xff08;media&#xff0…

蓝桥杯最后一战

目录 分巧克力_二分 题目描述 输入格式 输出格式 输入输出样例 说明/提示 代码&#xff1a; 巧克力 - 优先队列 题目描述 输入格式 输出格式 输入输出样例 说明/提示 代码&#xff1a; 思路分析&#xff1a; 秘密行动_dp 蓝桥杯算法提高-秘密行动 题目描述 …

Unity之OpenXR+XR Interaction Toolkit 安装和配置

前言 XR Interaction Toolkit 是Unity基于OpenXR标准&#xff0c;发布的一套XR工具&#xff0c;目的是方便我们快速接入XR相关的SDK&#xff0c;并且做到兼容不同VR设备的目的&#xff0c;目前流行的VR设备如Oculus&#xff0c;Metal&#xff0c;HTC Vive&#xff0c;Pico等统…

改进YOLOv8 | 主干网络篇 | YOLOv8 更换骨干网络之 MobileNetV3 | 《搜寻 MobileNetV3》

论文地址:https://arxiv.org/abs/1905.02244 代码地址:https://github.com/xiaolai-sqlai/mobilenetv3 我们展示了基于互补搜索技术和新颖架构设计相结合的下一代 MobileNets。MobileNetV3通过结合硬件感知网络架构搜索(NAS)和 NetAdapt算法对移动设计如何协同工作,利用互…

【天秤座区块链】元宇宙知识普以及简单解读清华研究报告

本节目录 温馨提示关于分栏【天秤座区块链】由来提前感受元宇宙区块链的两个注意点区块链革命简单认识清华大学报告解读&#xff08;元宇宙&#xff09;前传《雪崩》元宇宙具体是什么&#xff1f;元宇宙不是什么&#xff1f;那为什么要冲击元宇宙呢&#xff1f; 小补充及感谢 温…

前端搭建打字通游戏(内附源码)

The sand accumulates to form a pagoda ✨ 写在前面✨ 打字通功能介绍✨ 页面搭建✨ 样式代码✨ 功能实现 ✨ 写在前面 上周我们实通过前端基础实现了名言生成器&#xff0c;当然很多伙伴再评论区提出了想法&#xff0c;后续我们会考虑实现的&#xff0c;今天还是继续按照我们…

java基础入门-06-【面向对象进阶(多态包final权限修饰符代码块)】

Java基础入门-06-【面向对象进阶&#xff08;多态&包&final&权限修饰符&代码块&#xff09;】 14、面向对象进阶&#xff08;多态&包&final&权限修饰符&代码块&#xff09;1.1 多态的形式1.2 多态的使用场景1.3 多态的定义和前提1.4 多态的运行…

嵌入式设备逆向所需的工具链

导语&#xff1a;本文介绍了嵌入式设备逆向所需的工具链。 相关的应用程序或工具有&#xff1a; UART(Universal Asynchronous Receiver Transmitter&#xff0c;通用异步收发器)&#xff1a; UBoot&#xff1b; Depthcharge&#xff1b; SPI (Serial Peripheral Interface…

利用文本描述替换万物(Inpaint-Anything-Description)

文章目录 引言安装Demo github&#xff1a; https://github.com/Atlas-wuu/Inpaint-Anything-Description 引言 前段时间看了万物分割SAM、文生图Stable Diffusion、开集检测Grounding DINO&#xff0c;它们之间可以互相补充&#xff0c;AIGC变得更加可控。Inpaint Anything将…

RK3568平台开发系列讲解(网络篇)Linux 的 socket 套接字

🚀返回专栏总目录 文章目录 一、套接字的数据结构1.1、struct socket 数据结构1.2、struct sock 数据结构二、套接字的初始化三、套接字与文件四、Socket Buffer沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 Linux 内核支持的套接字如下: 我们创建套接字时,可以…

PCIe物理层弹性缓存机制(详细)解析-PCIe专题知识(四)

目录 前言一、简介二、详细解析2.1 实例解析2.2 具体实现过程 三、总结四、其他相关链接1、PCI总线及发展历程总结2、PCIe物理层总结-PCIE专题知识&#xff08;一&#xff09;3、PCIe数据链路层图文总结-PCIe专题知识&#xff08;二&#xff09;4、PCIe物理层链路训练和初始化总…

国产ChatGPT命名图鉴

很久不见这般热闹的春天。 随着ChatGPT的威名席卷全球&#xff0c;大洋对岸的中国厂商也纷纷亮剑&#xff0c;各式本土大模型你方唱罢我登场&#xff0c;声势浩大的发布会排满日程表。 有趣的是&#xff0c;在这些大模型产品初入历史舞台之时&#xff0c;带给世人的第一印象其…

进程替换函数组介绍exec*

目录 前述 execl execlp execle execv execvp execvpe 前述 介绍后缀的意义&#xff1a; l &#xff08;list&#xff09;&#xff1a;表示参数采用列表。 v&#xff08;vector&#xff09;&#xff1a;参数同数组表示。 p&#xff08;path&#xff09;&#xff1a;自…

力扣题库刷题笔记704-二分查找

1、题目如下&#xff1a; 2、个人Python代码如下&#xff1a; 个人代码如下&#xff1a; class Solution: def search(self, nums: List[int], target: int) -> int: left 0 right len(nums) - 1 while left < right: mid (right left) >> 1 if nums[mid] >…

【C++类和对象之拷贝构造、赋值运算符重载】

拷贝构造、赋值运算符重载 ❀拷贝构造函数 特性 ❀赋值运算符重载 赋值运算符重载格式 &#x1f340;小结&#x1f340; &#x1f389;博客主页&#xff1a;小智_x0___0x_ &#x1f389;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f389;系列…