想要精通算法和SQL的成长之路 - 最长递增子序列 II(线段树的运用)

想要精通算法和SQL的成长之路 - 最长递增子序列 II(线段树的运用)

  • 前言
  • 一. 最长递增子序列 II
    • 1.1 向下递推
    • 1.2 向上递推
    • 1.3 更新操作
    • 1.4 查询操作
    • 1.5 完整代码:

前言

想要精通算法和SQL的成长之路 - 系列导航

一. 最长递增子序列 II

原题链接
在这里插入图片描述

在做这个题目之前,先看一下:数据结构 - 线段树的运用 。

在线段树的基础上,思路如下:

  1. 首先,题目要求了子序列中,相邻的元素差不能超过 k 值。我们假设线段树的val值,存储的就是最长递增子序列的长度。
  2. 我们定义query函数的返回就是范围区间内的最长递增子序列长度。

那么伪代码就是:

public int lengthOfLIS(int[] nums, int k) {int ans = 0;for (int i = 0; i < nums.length; i++) {int tmp = query(nums[i]);ans = Math.max(ans, tmp);}return ans;
}

但是有一个问题:假设我们以num[i]作为最后一个元素,但是我并不知道它的前一个元素是谁。那咋办?

结合线段树的一个区间求值性质,我们只要求得区间 [num[i] - k, num[i] - 1] 之间的最长子序列长度,再加上1(当前子序列的最后一个元素num[i]),那么就可以求得以num[i]为结尾的最长子序列长度了。

同时我们还要更新各个子区间对应的最长长度,即伪代码:

for (int i = 0; i < nums.length; i++) {int tmp = query(nums[i]);update(tmp)ans = Math.max(ans, tmp);
}

1.1 向下递推

我们做更新操作的时候,求得不再是 数据结构 - 线段树的运用 里面的区间和,而是最大值。因此我们不能在原本值的基础上做加减法运算。而是做覆盖运算。

class Node {Node left, right;int val, add;
}private void pushDown(Node node) {if (node.left == null) {node.left = new Node();}if (node.right == null) {node.right = new Node();}if (node.add == 0) {return;}node.left.val = node.add;  // 替换node.right.val = node.add; // 替换node.left.add = node.add;  // 替换node.right.add = node.add; // 替换node.add = 0;
}

1.2 向上递推

求以当前节点作为最长子序列的最后一个元素时的序列长度时,我们可以拿到:

  • 左子序列的最长递增长度。
  • 右子序列的最长递增长度。

两者取最大,那么代码就是:

private void pushUp(Node node) {node.val = Math.max(node.left.val, node.right.val);
}

1.3 更新操作

public void update(Node node, int start, int end, int left, int right, int val) {// 如果线段树的区间完全在查询区间内,那么直接更新当前节点的 val 值即可if (start >= left && end <= right) {// 覆盖旧值node.val = val;// 覆盖需要传递的节点值node.add = val;return;}// 如果不在查询区间内,那么我们需要递归更新左右子树int mid = (start + end) >> 1;// 向下传递标记pushDown(node);if (left <= mid) {update(node.left, start, mid, left, right, val);}// [mid + 1, end] 和 [l, r] 可能有交集,遍历右孩子区间if (right > mid) {update(node.right, mid + 1, end, left, right, val);}// 计算当前节点的val值pushUp(node);
}

1.4 查询操作

public int query(Node node, int start, int end, int left, int right) {// 若当前区间完全在查询区间内,直接返回当前区间的最值if (left <= start && end <= right) {return node.val;}// 把当前区间 [start, end] 均分得到左右孩子的区间范围int mid = (start + end) >> 1, ans = 0;// 下推标记pushDown(node);// [start, mid] 和 [l, r] 可能有交集,遍历左孩子区间if (left <= mid) {ans = query(node.left, start, mid, left, right);}// [mid + 1, end] 和 [l, r] 可能有交集,遍历右孩子区间if (right > mid) {ans = Math.max(ans, query(node.right, mid + 1, end, left, right));}return ans;
}

1.5 完整代码:

有个问题就是:我们在遍历数组的每个元素num[i]的时候,我们的线段树区间应该设置为多少?
因为我们是以每个元素的 [num[i] - k, num[i] - 1]区间来做计算的,因此线段树的范围和num[i]的范围有关系。

题目有个提示:

在这里插入图片描述

那么确定好了线段树的区间范围,我们可以编写代码如下:

class Solution {public int lengthOfLIS(int[] nums, int k) {int ans = 0;Node root = new Node();for (int i = 0; i < nums.length; i++) {// 查询区间 [nums[i] - k, nums[i] - 1] 区间范围内的,以每个元素为末尾元素时的最长递增子序列长度。int cnt = query(root, 0, N, Math.max(0, nums[i] - k), nums[i] - 1) + 1;// 更新,注意这里是覆盖更新,对应的模版中覆盖更新不需要累加,已在下方代码中标注update(root, 0, N, nums[i], nums[i], cnt);ans = Math.max(ans, cnt);}return ans;}class Node {Node left, right;int val, add;}private int N = (int) 1e5;private Node root = new Node();public void update(Node node, int start, int end, int left, int right, int val) {// 如果线段树的区间完全在查询区间内,那么直接更新当前节点的 val 值即可if (start >= left && end <= right) {// 覆盖旧值node.val = val;// 覆盖需要传递的节点值node.add = val;return;}// 如果不在查询区间内,那么我们需要递归更新左右子树int mid = (start + end) >> 1;// 向下传递标记pushDown(node);if (left <= mid) {update(node.left, start, mid, left, right, val);}// [mid + 1, end] 和 [l, r] 可能有交集,遍历右孩子区间if (right > mid) {update(node.right, mid + 1, end, left, right, val);}// 计算当前节点的val值pushUp(node);}public int query(Node node, int start, int end, int left, int right) {// 若当前区间完全在查询区间内,直接返回当前区间的最值if (left <= start && end <= right) {return node.val;}// 把当前区间 [start, end] 均分得到左右孩子的区间范围int mid = (start + end) >> 1, ans = 0;// 下推标记pushDown(node);// [start, mid] 和 [l, r] 可能有交集,遍历左孩子区间if (left <= mid) {ans = query(node.left, start, mid, left, right);}// [mid + 1, end] 和 [l, r] 可能有交集,遍历右孩子区间if (right > mid) {ans = Math.max(ans, query(node.right, mid + 1, end, left, right));}return ans;}private void pushUp(Node node) {node.val = Math.max(node.left.val, node.right.val);}private void pushDown(Node node) {if (node.left == null) {node.left = new Node();}if (node.right == null) {node.right = new Node();}if (node.add == 0) {return;}node.left.add = node.add;  // 不需要累加node.right.add = node.add; // 不需要累加node.left.val = node.add;  // 不需要累加node.right.val = node.add; // 不需要累加node.add = 0;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单链表详细解析|画图理解

前言&#xff1a; 在前面我们学习了顺序表&#xff0c;相当于数据结构的凉菜&#xff0c;今天我们正式开始数据结构的硬菜了&#xff0c;那就是链表&#xff0c;链表有多种结构&#xff0c;但我们实际中最常用的还是无头单向非循环链表和带头双向循环链表&#xff0c;我们今天先…

idea没有maven工具栏解决方法

背景&#xff1a;接手的一些旧项目&#xff0c;有pom文件&#xff0c;但是用idea打开的时候&#xff0c;没有认为是maven文件&#xff0c;所以没有maven工具栏&#xff0c;不能进行重新加载pom文件中的依赖。 解决方法&#xff1a;选中pom.xml文件&#xff0c;右键 选择添加为…

Denoising diffusion implicit models 阅读笔记

Denoising diffusion probabilistic models (DDPMs)从马尔科夫链中采样生成样本&#xff0c;需要迭代多次&#xff0c;速度较慢。Denoising diffusion implicit models (DDIMs)的提出是为了加速采样过程&#xff0c;减少迭代的次数&#xff0c;并且要求DDIM可以复用DDPM训练的网…

计算机网络补充

未分类文档 CDMA是码分多路复用技术 和CMSA不是一个东西 UPD是只确保发送 但是接收端收到之后(使用检验和校验 除了检验的部分相加 对比检验和是否相等。如果不相同就丢弃。 复用和分用是发生在上层和下层的问题。通过比如时分多路复用 频分多路复用等。TCP IP 应用层的IO多路…

绿色计算产业发展白皮书:2022年OceanBase助力蚂蚁集团减排4392tCO2e

9 月 15 日&#xff0c;绿色计算产业联盟在 2023 世界计算大会期间重磅发布了《绿色计算产业发展白皮书&#xff08;2023 版&#xff09;》。蚂蚁集团作为指导单位之一&#xff0c;联合参与了该白皮书的撰写。 白皮书中指出&#xff0c;落实“双碳”战略&#xff0c;绿色计算已…

基于微信小程序的场地预约系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

亮相“外滩金融峰会” 百望云实力入选“融城杯金融科技创新十佳案例”

近日&#xff0c;第五届“外滩金融峰会”在上海召开&#xff0c;百望云受邀出席峰会&#xff0c;与全球财经政要、机构高管与学界领袖齐聚外滩&#xff0c;分享真知灼见&#xff0c;以对话推动共识。 本届峰会由中国金融四十人论坛&#xff08;CF40&#xff09;与中国国际经济交…

electron之快速上手

前一篇文章已经介绍了如何创建一个electron项目&#xff0c;没有看过的小伙伴可以去实操一下。 接下来给大家介绍一下electron项目的架构是什么样的。 electron之快速上手 electron项目一般有两个进程&#xff1a;主进程和渲染进程。 主进程&#xff1a;整个项目的唯一入口&…

HashMap 源码解读(JDK1.8)

一、HashMap说明 基于哈希表的 Map 接口实现。此实现提供所有可选的map操作&#xff0c;并允许空值和空键。&#xff08;HashMap 类大致等同于 Hashtable&#xff0c;只是它不支持同步并且允许空值。&#xff09;此类不保证插入键值的顺序&#xff1b;特别是&#xff0c;它不保…

Mendix中的依赖管理:npm和Maven的应用

序言 在传统java开发项目中&#xff0c;我们可以利用maven来管理jar包依赖&#xff0c;但在mendix项目开发Custom Java Action时&#xff0c;由于目录结构有一些差异&#xff0c;我们需要自行配置。同样的&#xff0c;在mendix项目开发Custom JavaScript Action时&#xff0c;…

48v转24v 3A 48v转12v 48v转5v电源芯片AH7691X

AH7691X是一款高-效-率、高-压降压型DC-DC转换器&#xff0c;采用固定110KHz的开关频率&#xff0c;具备3A的输出电流能力&#xff0c;低纹波&#xff0c;并且具备***软启动功能、过压保护功能和温度保护。该器件还集成了峰值限流功能&#xff0c;简化了电路设计。 AH7691X内部…

MFC 绘图

效果图&#xff1a;三张bmp图 字 竖线 组成 在OnPaint()函数中 CPaintDC dc(this);CRect rect;GetClientRect(&rect); //获取客户区矩形CDC dcBmp; //定义并创建一个内存设备环境dcBmp.CreateCompatibleDC(&dc); //创建兼容性DCCBitmap …

【kafka实战】01 3分钟在Linux上安装kafka

本节采用docker安装Kafka。采用的是bitnami的镜像。Bitnami是一个提供各种流行应用的Docker镜像和软件包的公司。采用docker的方式3分钟就可以把我们想安装的程序运行起来&#xff0c;不得不说真的很方便啊&#xff0c;好了&#xff0c;开搞。使用前提&#xff1a;Linux虚拟机&…

AKKA 互相调用

SpringBoot 集成 AKKA 可以参考此文&#xff1a;SpringBoot 集成 AKKA 场景1&#xff1a;bossActor 收到信息&#xff0c;然后发给 worker1Actor 和 worker2Actor controller 入口&#xff0c;初次调用 ActorRef.noSender() Tag(name "test") RestController Req…

【MATLAB第77期】基于MATLAB代理模型算法的降维/特征排序/数据处理回归/分类问题MATLAB代码实现【更新中】

【MATLAB第77期】基于MATLAB代理模型算法的降维/特征排序/数据处理回归/分类问题MATLAB代码实现 本文介绍基于libsvm代理模型算法的特征排序方法合集&#xff0c;包括&#xff1a; 1.基于每个特征预测精度进行排序&#xff08;libsvm代理模型&#xff09; 2.基于相关系数corr的…

前端技术社区总目录

前端技术社区欢迎您的订阅。订阅后&#xff0c;您将可以查看以下所有博客内容。 注&#xff1a;专栏内容主要面向新手 注&#xff1a;每个示例都有相对应的完整代码 注&#xff1a;该专栏博客内容将会逐步迁移至https://blog.csdn.net/m0_60387551/article/details/128017725 …

用于自然语言处理的 Python:理解文本数据

一、说明 Python是一种功能强大的编程语言&#xff0c;在自然语言处理&#xff08;NLP&#xff09;领域获得了极大的普及。凭借其丰富的库集&#xff0c;Python 为处理和分析文本数据提供了一个全面的生态系统。在本文中&#xff0c;我们将介绍 Python for NLP 的一些基础知识&…

Sound/播放提示音, Haptics/触觉反馈, LocalNotification/本地通知 的使用

1. Sound 播放提示音 1.1 音频文件: tada.mp3&#xff0c; badum.mp3 1.2 文件位置截图: 1.3 实现 import AVKit/// 音频管理器 class SoundManager{// 单例对象 Singletonstatic let instance SoundManager()// 音频播放var player: AVAudioPlayer?enum SoundOption: Stri…

【C++】stack queue

stack & queue 一、容器适配器二、deque&#xff08;了解&#xff09;三、stack1. stack 的介绍2. 模拟实现 stack 四、queue1. queue 的使用2. 模拟实现 queue3. priority_queue&#xff08;1&#xff09;priority_queue 的介绍&#xff08;2&#xff09;priority_queue 的…

从零开始—【Mac系统】MacOS配置Java环境变量

系统环境说明 Apple M1 macOS Ventura 版本13.5.2 1.下载JDK安装包 Oracle官网下载地址 JDK下载【注&#xff1a;推荐下载JDK8 Oracle官网JDK8下载】 关于JDK、JRE、JVM的关系说明 JDK(Java Development Kit&#xff0c;Java开发工具包) &#xff0c;是整个JAVA的核心&#…