LeetCoed 2, 23, 25, 112, 113

文章目录

  • 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.mfbz.cn/a/18392.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

三分钟教你Mac下安装VmWare虚拟机

大数据课程课前环境准备&#xff1a;mac中安装三台linux服务器 一、课前准备 准备一台内存最少8G&#xff08;建议16G&#xff09;、cpu i7 4核的电脑 二、课堂主题 安装虚拟化软件VMware准备3台linux虚拟机 三、课堂目标 完成mac下3个虚拟机的安装 四、知识要点 文档说…

浅析智慧充电桩云平台的技术设计方案

自从我国提出“新基建”以来&#xff0c;充电基础设施产业也成为行业的话题与关注焦点。据数据统计&#xff0c;2021年&#xff0c;中国新能源汽车保有量达到784万辆&#xff0c;预计2025年&#xff0c;中国新能源汽车保有量达到2672万辆&#xff0c;2025年充电桩数量将达到654…

【沐风老师】一步一步教你在3dMax中进行UVW贴图和展开UVW的方法

将简单或程序材质应用于对象并不难。但是当表面需要在其上显示某种纹理时&#xff0c;它会变得更加复杂。任何纹理贴图都放在材质的 Diffuse 插槽中&#xff0c;但渲染的结果可能无法预测。这就是为什么我们需要了解 3DMAX 如何将纹理应用于 3D 对象&#xff0c;什么是 UVW 贴图…

weblogic ssrf 漏洞复现

一.前言 Weblogic中存在一个SSRF漏洞&#xff0c;利用该漏洞可以发送任意HTTP请求&#xff0c;进而攻击内网中redis、fastcgi等脆弱组件。 二.环境搭建 在docker中开启环境 sudo docker-compose up -d sudo docker-compose ps #查看状态访问http://your-ip:7001/uddiexpl…

【数码】收音机,德生PL380使用教程与注意事项

文章目录 1、主界面功能介绍&#xff08;注意闹钟和自动关机&#xff09;2、电池和电池模式的匹配3、收音机天线与信号&#xff0c;耳机与噪音F、参考资料 1、主界面功能介绍&#xff08;注意闹钟和自动关机&#xff09; 红色的按钮&#xff1a;power 按一下开机&#xff0c;按…

25个著名的WordPress网站案例

想创建免费网站吗&#xff1f;从易服客建站平台开始 500M免费空间&#xff0c;可升级为20GB电子商务网站 创建免费网站 WordPress 内容管理系统为全球35%的网站提供支持。鉴于目前有 17 亿个站点&#xff0c;并且还在增加&#xff0c;您可以算出每秒向网站访问者提供内容的W…

牛客网剑指offer|中等题day2|JZ22链表中倒数最后k个结点(简单)、JZ35复杂链表的复制(复杂)、JZ77按之字形顺序打印二叉树(中等)

JZ22链表中倒数最后k个结点(简单) 链接&#xff1a;链表中倒数最后k个结点_牛客题霸_牛客网 /*** struct ListNode {* int val;* struct ListNode *next;* ListNode(int x) : val(x), next(nullptr) {}* };*/ class Solution { public:/*** 代码中的类名、方法名、参数名已经指…

一、PEMFC基础之热力学

一、PEMFC基础之热力学 1.内能U、焓H、熵S、吉布斯自由能G、赫姆霍兹自由能F关系图2.可逆电压与温度和压力的关系3.能斯特方程4.燃料电池效率 1.内能U、焓H、熵S、吉布斯自由能G、赫姆霍兹自由能F关系图 2.可逆电压与温度和压力的关系 标准状态可逆电压Er计算&#xff1a; E …

基于springboot的4S店车辆管理系统(源码等)

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&…

Linux进程状态及优先级

本文已收录至《Linux知识与编程》专栏&#xff01; 作者&#xff1a;ARMCSKGT 演示环境&#xff1a;CentOS 7 进程状态及优先级 前言正文进程状态就绪运行状态R阻塞睡眠状态 S休眠状态D挂起 暂停状态T前台与后台进程待追踪暂停状态t 死亡状态 X僵尸状态 Z 孤儿进程进程优先级查…

美颜SDK的隐私保护与安全性分析

随着智能手机和移动应用的普及&#xff0c;美颜SDK已经成为了很多应用的标配。美颜SDK的使用可以让用户在拍照或者视频聊天时&#xff0c;实现自拍美颜、滤镜、磨皮、瘦脸等效果。但是&#xff0c;在享受美颜SDK带来的便利的同时&#xff0c;我们也需要关注美颜SDK的隐私保护与…

配置文件Application.properties

配置文件Application.properties 属性配置配置文件的多种格式yaml的数据格式读取yaml文件中的属性值读取yaml文件中的全部属性yaml文件 数据库的属性 属性配置 在application.properties中添加server.port端口号即可 # 服务器端口配置 server.port80# 修改banner 关闭banner …

两分钟成为 ChatGPT 国内高手【不要再拿ChatGPT当百度用了】

不要再问ChatGPT那些问百度的问题了&#xff0c;有更进阶的用法 更高效的编写prompts&#xff0c;以便ChatGPT给出更精准的回答 但是需要注意的是&#xff1a;国内现在根本没有GPT-4使用&#xff0c;但凡是说有GPT-4的都是骗子。 GPT 可以写文章&#xff0c;可以写诗&#x…

MATLAB实现建筑热平衡模型建立及节能温控方案

全球大约1/3的能源消耗于建筑。在能源紧张的今天&#xff0c;如何减少建筑的能源浪费是一个值得研究的课题。 本文在综合国内外建筑能耗模拟方法的基础上&#xff0c;采用热平衡法&#xff0c;针对一小型建筑建立了热特性仿真模型&#xff0c;选用武汉地区的气象数据&#xff…

快递出入库管理APP开发 收发快递更方便

网购的盛行让收发快递成为很多人日常生活必不可少的一个环节&#xff0c;对于快递公司来说&#xff0c;每天有那么多的快递&#xff0c;如果没有一个好用的管理系统的话&#xff0c;不仅麻烦还很容易出现纰漏&#xff0c;所以快递出入库管理APP软件就显得很必要了。 快递…

【ChatGPT】你会是被AI抢饭碗的那类人吗?

文章目录 前言一、AI替代“基础性工作”&#xff0c;二、AI没有魔法&#xff1a;人类做不到&#xff0c;它也做不到三 人类的恐惧&#xff1a;被替代、被超越四 AI让语言返祖&#xff0c;小语种与文化“濒危灭绝”五 人类的未来&#xff0c;教育何去何从&#xff1f;总结 前言 …

浅谈jmeter性能测试步骤入门

一、Jmeter简介 1 概述 jmeter是一个软件&#xff0c;使负载测试或业绩为导向的业务&#xff08;功能&#xff09;测试不同的协议或技术。 它是 Apache 软件基金会的Stefano Mazzocchi JMeter 最初开发的。 它主要对 Apache JServ&#xff08;现在称为如 Apache Tomca…

[ tool ] Xpath选择器和selenium工具基本使用

XPath xpath介绍 是一门在XML文档中查找信息的语言 html文档准备 doc <html><head><base hrefhttp://example.com/ /><title>Example website</title></head><body><div idimages><a hrefimage1.html aabb>Name: My…

【镜像取证篇】仿真碎片-记一次镜像仿真失败的复盘过程

【镜像取证篇】仿真碎片-记一次镜像仿真失败的复盘过程 这个是很久以前的一个镜像实验&#xff0c;当时仿真可以看到Windows的启动界面&#xff0c;但却一直无法正常进入系统&#xff0c;不断的尝试修复&#xff0c;都是显示错误&#xff0c;最后把类型改为IDE后&#xff0c;成…

Kotlin高级协程

Kotlin高级协程 一.前言二.先从线程说起三.协程的设计思想四.协程特点&#xff1a;优雅的实现移步任务五.协程基本使用六.协程和线程相比有什么特点&#xff0c;如何优雅的实现异步任务 一.前言 在文章正式上干货之前&#xff0c;先说一点背景吧&#xff1b;我是 Kotlin 协程官…