最长递增子序列 - LeetCode 热题 87

大家好!我是曾续缘💖

今天是《LeetCode 热题 100》系列

发车第 87 天

动态规划第 7 题

❤️点赞 👍 收藏 ⭐再看,养成习惯

最长递增子序列

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

 

示例 1:

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。

示例 2:

输入:nums = [0,1,0,3,2,3]
输出:4

示例 3:

输入:nums = [7,7,7,7,7,7,7]
输出:1

提示:

  • 1 <= nums.length <= 2500
  • -104 <= nums[i] <= 104

进阶:

  • 你能将算法的时间复杂度降低到 O(n log(n)) 吗?
难度:💖💖

解题方法

定义f[i]为:长度为k+1的子序列的末尾元素。下标代表了长度,值代表的是原数组中的一个值,作为子序列的末尾元素。

初始化

  • f数组的长度为0,很好理解吧,不存在下标,即不存在任何长度的子序列。

遍历数组进行状态转移

  1. 因为我们是一个数一个数地遍历的,对于当前遍历的数num,尝试把它加到目前最长子序列的末尾。

    • 目前最长子序列的末尾在哪里呢?根据f的定义,最长子序列的长度就是f最大的下标加1,最长子序列的末尾元素就是f[最大的下标]
    • 目前遍历的数num能不能加到目前最长子序列的末尾呢?如果num大于目前最长子序列的末尾元素f[最大的下标],说明递增,可以加入。
    • 加入之后会导致什么呢?最长子序列的长度+1了,末尾元素也改变了,变成了num
    • 最长子序列的长度变化了,怎么办呢,怎么改呢?根据f的定义,f的最大下标要加1了,说明最长子序列长度+1了,同时f[新最大下标]等于num了,因为最长子序列的尾部是当前遍历的num了。
    • f数组的最大下标+1了,也填入值了,原来的f最大下标的值需要改吗?不需要,因为这个下标对应的子序列长度没变化啊,我们也不愿意将num作为它的尾部,因为num更大,不利于贪心。
  2. 如果num不能加到目前最长子序列的末尾,说明最长子序列的长度不会变化。

    • 那我要num有何用?我们可以用num来替换掉其他长度的子序列的尾部啊,让它们变小点,方便后面新增的数能更小的拼接上来。
    • 好,我们从头遍历f数组,不断尝试更新f[i]的尾部元素,和num取min,越小越好。
    • 但是这样算法时间复杂度就变成了 O ( n 2 ) O(n^2) O(n2)
    • 想想我们有必要更新所有的f值吗?比如说长度为1,2,3的子序列的尾部,都能更新为更小的num。我们更新了3,还有必要更新1,2吗?更新了也不会导致子序列的长度变长,就算后面有数拼接上来,我们也是选择拼接在长度为3的子序列上啊,因为贪它更长啊。
    • 所以我们选择更新最后一个能更新的,之前的不用考虑了。
    • 如何找到最后一个能更新的位置呢?这显然和我们的lowerbound方法不谋而合。使用二分的方法,以 O ( l o g n ) O(logn) O(logn)的时间复杂度迅速找到最后一个能将尾部更新为numf数组下标,更新之。
      • 为什么能用二分呢?eeee因为f数组是递增的。

返回值:根据f的定义,最长子序列的长度就是f的最大下标+1,即f数组的长度。

Code

class Solution {public int lengthOfLIS(int[] nums) {List<Integer> f = new ArrayList<>();for (int num : nums) {if (f.isEmpty() || num > f.get(f.size() - 1)) {f.add(num);} else {int l = lowerbound(f, num);f.set(l, num);}}return f.size();}public int lowerbound(List<Integer> f, int num) {int l = 0, r = f.size() - 1;while (l <= r) {int mid = (l + r) / 2;if (f.get(mid) >= num) {r = mid - 1;} else {l = mid + 1;}}return l;}
}

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

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

相关文章

diffusers 使用脚本导入自定义数据集

在训练扩散模型时&#xff0c;如果附加额外的条件图片数据&#xff0c;则需要我们准备相应的数据集。此时我们可以使用官网提供的脚本模板来控制导入我们需要的数据。 您可以参考官方的教程来实现具体的功能需求&#xff0c;为了更加简洁&#xff0c;我将简单描述一下整个流程…

CentOS 7基础操作13_Linux下添加、修改、删除用户账号

1、添加、修改、删除用户账号 1&#xff09;useradd命令——添加用户账号。 useradd [选项] 用户名 最简单的用法是&#xff0c;不添加任何选项&#xff0e;只使用用户名作为useradd命令的参数&#xff0c;按系统默认配置建立指定的用户账号。在CentOS系统中&#xff0…

融云:应用出海新增长引擎,GPT-4o 后的 AI 创新与用户运营

近日&#xff0c;融云与 TikTok、维卓联合在京举办了“十年出海&#xff0c;遇上 AI”私享会。 会上&#xff0c;融云解决方案架构师于洪达带来了《应用出海新增长引擎&#xff0c;AI 创新与用户精细化运营》主题分享&#xff0c;探讨在 AI 技术大潮下应用出海通过创新运营方式…

从0开发一个Chrome插件:背景脚本实战——开发一个显示当前时间的小功能

前言 这是《从0开发一个Chrome插件》系列的第八篇文章,本系列教你如何从0去开发一个Chrome插件,每篇文章都会好好打磨,写清楚我在开发过程遇到的问题,还有开发经验和技巧。 专栏: 从0开发一个Chrome插件:什么是Chrome插件?从0开发一个Chrome插件:开发Chrome插件的必要…

等级保护2.0新变化

等级保护2.0&#xff1a;新时代网络安全的新篇章 引言 随着信息技术的飞速发展&#xff0c;网络安全已成为国家安全的重要组成部分。等级保护2.0作为我国网络安全等级保护制度的最新标准&#xff0c;标志着我国网络安全等级保护工作迈入了新时代。本文将探讨等级保护2.0的新变…

金融科技:跨境支付的新引擎,开启全球化支付新时代

一、引言 在全球经济一体化的今天,跨境支付作为连接各国经贸往来的重要桥梁,其便捷性、安全性和效率性成为了各国企业和消费者关注的焦点。金融科技,作为现代金融与传统科技深度融合的产物,正以其独特的创新力和推动力,成为跨境支付领域的新引擎,引领着全球化支付新时代…

java应用性能优化思路(一)

1.动静分离&#xff0c;将静态资源交给nginx管理&#xff0c;动态请求交给我们开发的应用程序处理&#xff1b; 2.为数据库表常用查询字段添加索引&#xff1b; 3.如果查询的sql语句还打印在控制台&#xff0c;需将日志级别提高到info或error; logging:level:com.atguigu.gu…

Visual Studio的快捷按键

Visual Studio的快捷按键对于提高编程效率至关重要。以下是一些常用的Visual Studio快捷按键&#xff0c;并按照功能进行分类和归纳&#xff1a; 1. 文件操作 Ctrl O&#xff1a;打开文件Ctrl S&#xff1a;保存文件Ctrl Shift S&#xff1a;全部保存Ctrl N&#xff1a;…

群体优化算法---灰狼优化算法学习介绍以及在卷积神经网络训练上的应用

**长文预警**介绍 在自然界中&#xff0c;狼群的社会结构和捕猎策略展现了高度的智能和协调性&#xff0c;灰狼优化算法&#xff08;Grey Wolf Optimizer, GWO&#xff09;正是受此启发提出的一种群体智能优化算法。GWO主要模拟了灰狼的社会等级制度和捕猎行为&#xff0c;其核…

深度学习 - 激活函数

深度学习 - 激活函数 激活函数&#xff08;Activation Function&#xff09;是神经网络中的关键组件&#xff0c;用于引入非线性&#xff0c;使得网络能够学习和表示复杂的模式和关系。以下是几种常见的激活函数及其详细解释&#xff1a; 1. Sigmoid&#xff08;S型激活函数&…

Playwright框架入门

自从2023年底playwright框架火起来之后,很多小伙伴咨询我们这个框架,甚至问我们什么时候出这个课程. 这步这个课程在我们千呼万唤中出来了.具体的课程大纲和试听可以联系下方二维码获取. 今天给大家分享一下playwright的安装和一些常用API,为后续的学习做好准备工作. Playwrig…

Unit9

Unit9 gene 基因&#xff0c;生产&#xff0c;类型 genetic genius ingenious generate generation degenerate genuine generous generosity gender genre homogeneous time 时间 time timely timer first-timer temporary temporarily tempo contemporary dra 戏剧…

欧智通恒玄BES2600W基于Openharmony v3.0的分布式软总线测试过程记录

恒玄BES2600W SoC 的欧智通的单板基于Openharmony v3.0的底座&#xff0c;其测试的样例代码是基于恒玄公司开发的轻量带屏显示产品样例代码&#xff0c;主要包括图形、软总线等特性产品的开发。 基础介绍&#xff1a; ​ L0的系统基于Liteos-m的m内核&#xff0c;网络使用lwi…

计算机网络--传输层

计算机网络--计算机网络概念 计算机网络--物理层 计算机网络--数据链路层 计算机网络--网络层 计算机网络--传输层 计算机网络--应用层 1. 概述 1.1 传输层的意义 网络层可以把数据从一个主机传送到另一个主机&#xff0c;但是没有和进程建立联系。 传输层就是讲进程和…

【中间件系列】浅析redis是否适合做消息队列

文章目录 一、简单的list消息队列1.命令示例2.伪代码示例3.方案优劣 二、Pub/Sub发布订阅1.消息丢失2.消息堆积 三、相对成熟的Stream1.redis命令介绍2.多消费者组测试3.Stream会持久化吗&#xff1f;4.消息堆积如何解决&#xff1f; 总结 用redis也是比较久了&#xff0c;并且…

Unity3d简单对话系统的实现——使用Dialogue editor完成对话系统

目录 前言 使用方法 1.下载dialogue editor 2.新建空物体 3.对对话内容进行编辑 4.对话画布建立 5.触发对话框代码 结束语 前言 今天是坚持写博客的第21天&#xff0c;很高兴自己可以坚持&#xff0c;也希望能与大家一起进步。我们今天来看unity3d当中的一个可以轻松实…

Feign是如何发送http请求的

1、接口定义 首先&#xff0c;开发者使用Feign提供的注解&#xff08;如FeignClient&#xff09;定义接口&#xff0c;并在接口中定义HTTP请求的方法&#xff0c;这些方法将映射到远程服务的具体HTTP请求。 2、动态代理 当应用启动时&#xff0c;Feign会通过动态代理和反射机…

Go select 语句使用场景

1. select介绍 select 是 Go 语言中的一种控制结构&#xff0c;用于在多个通信操作中选择一个可执行的操作。它可以协调多个 channel 的读写操作&#xff0c;使得我们能够在多个 channel 中进行非阻塞的数据传输、同步和控制。 基本语法&#xff1a; select {case communica…

Python中的函数式编程特性深入探讨

Python中的函数式编程特性深入探讨 Python,作为一种多范式编程语言,不仅支持面向对象编程(OOP),同样也对函数式编程(FP)提供了良好的支持。函数式编程是一种编程范式,它将计算机程序看作是一系列函数的求值,并避免使用可变状态和共享状态。本文将深入探讨Python中的函…

数据赋能(112)——体系:监控数据采集——影响因素、直接作用、主要特征

影响因素 影响监控数据采集的主要影响因素如下&#xff1a; 采样率&#xff1a;采样率是指采集数据的频率。采样率决定了监控的实时性与精确度&#xff0c;一般来说&#xff0c;采样率越高&#xff0c;监控的实时性就越高&#xff0c;精确度也越高。但是&#xff0c;过高的采…