【LeetCode】动态规划—673. 最长递增子序列的个数(附完整Python/C++代码)

动态规划—673. 最长递增子序列的个数

  • 前言
  • 题目描述
  • 基本思路
    • 1. 问题定义
    • 2. 理解问题和递推关系
    • 3. 解决方法
      • 3.1 动态规划方法
      • 3.2 优化方法
    • 4. 进一步优化
    • 5. 小总结
  • 代码实现
    • Python
      • Python3代码实现
      • Python 代码解释
    • C++
      • C++代码实现
      • C++ 代码解释
        • 1. 初始化:
        • 2. 动态规划过程:
        • 3. 计算结果:
  • 总结:

前言

在算法研究中,序列问题是一个常见而重要的主题。最长递增子序列问题不仅在理论上具有挑战性,同时在许多实际应用中也非常有用,如数据分析、动态规划和计算机视觉等领域。本文将深入探讨如何利用动态规划和计数技巧来解决该问题,同时提供 Python 和 C++ 的具体实现,以帮助读者更好地理解和掌握这一算法。

题目描述

在这里插入图片描述

基本思路

1. 问题定义

给定一个整数数组 nums,我们需要找到其中最长的递增子序列的长度,以及该长度的递增子序列的个数。

2. 理解问题和递推关系

  • 最长递增子序列(LIS)是指在数组中选择若干元素,使得它们的顺序与原数组相同,且毎个元素都大于前一个元素。

・ 定义 dp[i] 为以 nums[i] 结尾的最长递增子序列的长度, count[i] 为以 nums[i] 结尾的最长递增子序列的个数。

・递推关采如下:
・对于每个 nums[i],音看其前面的所有元素 nums[j]( j < i )

  • 如果 nums[j] < nums[i], 则更新 dp[i] :

d p [ i ] = max ⁡ ( d p [ i ] , d p [ j ] + 1 ) d p[i]=\max (d p[i], d p[j]+1) dp[i]=max(dp[i],dp[j]+1)

  • 更新 count[i]:
  • 如果 d p [ j ] + 1 > d p [ i ] d p[j]+1>d p[i] dp[j]+1>dp[i] ,说明找到了一个更长的递增子序列,更新 count[i]count[j]
  • 如果 d p [ j ] + 1 = = d p [ i ] d p[j]+1==d p[i] dp[j]+1==dp[i] ,说明找到了一个同样长度的递增子序列,累加 count[j]count[i]

3. 解决方法

3.1 动态规划方法

  1. 初始化两个数组 d p d p dpcount, 长度与 nums 相同:
    • dp[i] 初始化为 1,因为每个元素本身可以形成长度为 1 的递增子序列。
    • count[i]初始化为 1 ,因为毎个元素自身的子序列个数为 1
  2. 使用双重矿环遍历数组 nums,更新 dp[i]count[i]数组。
  3. 最终,找到 max ⁡ ( d p ) \max (\mathrm{dp}) max(dp) 来获取最长递增子序列的长度,并对 count 数组进行遍历,累加所有 count[i] (当 dp[i] 等于最长长度) 以获得该长度子序列的个数。

3.2 优化方法

  • 使用二分查找技术可以进一步优化 d p d p dp 数组的构建,使时间复杂度降低到 O ( n log ⁡ n ) O(n \log n) O(nlogn)

  • 通过维护一个数组 tails 来记录当前长度的递增子序列的末尾元素,从而更新 count

4. 进一步优化

  • 利用 bisect 库可以方便地在 tails 中找到合适的位置,并更新计数,进一步提高效率。

5. 小总结

  • 本文通过动态规划方法有效解决了计算最长递增子序列及其个数的问题。
  • 该问题展示了动态规划与计数相结合的技巧,适用于类似的序列问题。

以上就是最长递增子序列的个数问题的基本思路。

代码实现

Python

Python3代码实现

class Solution:def findNumberOfLIS(self, nums):if not nums:return 0n = len(nums)dp = [1] * n  # 初始化 dp 数组count = [1] * n  # 初始化 count 数组for i in range(n):  # 遍历每个元素for j in range(i):  # 检查前面的元素if nums[j] < nums[i]:  # 如果找到较小的元素if dp[j] + 1 > dp[i]:  # 找到更长的递增子序列dp[i] = dp[j] + 1count[i] = count[j]  # 更新个数elif dp[j] + 1 == dp[i]:  # 找到相同长度的递增子序列count[i] += count[j]  # 累加个数max_length = max(dp)  # 获取最长递增子序列的长度return sum(count[i] for i in range(n) if dp[i] == max_length)  # 返回该长度的个数

Python 代码解释

  • 初始化:创建 dpcount 数组,分别存储最长递增子序列的长度和个数。
  • 双重循环:外层循环遍历每个元素,内层循环检查之前的元素,更新 dpcount 数组。
  • 返回结果:找到 max(dp),然后累加所有 count[i](当 dp[i] 等于最大长度)以获得结果。

C++

C++代码实现

class Solution {
public:int findNumberOfLIS(vector<int>& nums) {if (nums.empty()) return 0;int n = nums.size();vector<int> dp(n, 1);  // dp[i] 表示以 nums[i] 结尾的最长上升子序列的长度vector<int> count(n, 1);  // count[i] 表示以 nums[i] 结尾的最长上升子序列的个数int max_length = 0;  // 记录最长上升子序列的长度int max_count = 0;   // 记录最长上升子序列的个数// 动态规划计算 dp 和 count 数组for (int i = 0; i < n; ++i) {for (int j = 0; j < i; ++j) {if (nums[i] > nums[j]) {if (dp[j] + 1 > dp[i]) {dp[i] = dp[j] + 1;  // 更新长度count[i] = count[j]; // 更新个数} else if (dp[j] + 1 == dp[i]) {count[i] += count[j]; // 追加个数}}}max_length = max(max_length, dp[i]); // 更新最大长度}// 计算最长上升子序列的总个数for (int i = 0; i < n; ++i) {if (dp[i] == max_length) {max_count += count[i]; // 统计个数}}return max_count; // 返回结果}
};

C++ 代码解释

1. 初始化:
  • dp[i] 用于存储以 nums[i] 结尾的最长上升子序列的长度。
  • count[i] 用于存储以 nums[i] 结尾的最长上升子序列的个数。
  • max_lengthmax_count 分别用于记录最长上升子序列的长度和个数。
2. 动态规划过程:
  • 外层循环遍历每个元素 i,内层循环遍历 i 之前的所有元素 j
  • 如果 nums[i] 大于 nums[j],检查是否形成了更长的上升子序列。
  • 如果找到了更长的序列,更新 dp[i]count[i];如果找到了相同长度的序列,增加 count[i]
3. 计算结果:
  • 遍历 dp 数组,统计最长上升子序列的总个数。

总结:

  • 本文通过对最长递增子序列及其个数问题的深入分析,展示了动态规划的强大能力。
  • 结合计数的技巧,使得解决方案不仅有效且易于理解,适合解决类似的复杂问题。

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

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

相关文章

FiBiNET模型实现推荐算法

1. 项目简介 A031-FiBiNET模型项目是一个基于深度学习的推荐系统算法实现&#xff0c;旨在提升推荐系统的性能和精度。该项目的背景源于当今互联网平台中&#xff0c;推荐算法在电商、社交、内容分发等领域的广泛应用。推荐系统通过分析用户的历史行为和兴趣偏好&#xff0c;预…

Django学习笔记十三:优秀案例学习

Django CMS 是一个基于 Django 框架的开源内容管理系统&#xff0c;它允许开发者轻松地创建和管理网站内容。Django CMS 提供了一个易于使用的界面来实现动态网站的快速开发&#xff0c;并且具有丰富的内容管理功能和多种插件扩展。以下是 Django CMS 的一些核心特性和如何开始…

opencv的相机标定与姿态解算

首先我们要知道四个重要的坐标系 世界坐标系相机坐标系图像成像坐标系图像像素坐标系 坐标系之间的转换 世界坐标系——相机坐标系 从世界坐标系到相机坐标系&#xff0c;涉及到旋转和平移&#xff08;其实所有的运动也可以用旋转矩阵和平移向量来描述&#xff09;。绕着不…

最新Prompt预设词指令教程大全ChatGPT、AI智能体(300+预设词应用)

使用指南 直接复制在AI工具助手中使用&#xff08;提问前&#xff09; 可以前往已经添加好Prompt预设的AI系统测试使用&#xff08;可自定义添加使用&#xff09; SparkAi系统现已支持自定义添加官方GPTs&#xff08;对专业领域更加专业&#xff0c;支持多模态文档&#xff0…

同三维T80001EHK 4K超高清HDMI编码器

【系列介绍】 同三维T80001EHK 4K超高清HDMI编码器 4K超高清编码器&#xff08;采集盒&#xff09;是专业的高清音视频编码产品&#xff0c;只需要占用较小的带宽&#xff0c;即可获得高清晰度的视频信号。该产品采用H.265编码格式&#xff0c;可同时对视频音频进行编码。输出…

【万字长文】Word2Vec计算详解(二)Skip-gram模型

【万字长文】Word2Vec计算详解&#xff08;二&#xff09;Skip-gram模型 写在前面 本篇介绍Word2Vec中的第二个模型Skip-gram模型 【万字长文】Word2Vec计算详解&#xff08;一&#xff09;CBOW模型 markdown行 9000 【万字长文】Word2Vec计算详解&#xff08;二&#xff09;S…

<Project-8.1 pdf2tx-MM> Python Flask 用浏览器翻译PDF内容 2个翻译引擎 繁简中文结果 从P8更改

更新 Project Name&#xff1a;pdf2tx (P6) Date: 5oct.24 Function: 在浏览器中翻译PDF文件 Code:https://blog.csdn.net/davenian/article/details/142723144 升级 Project Name: pdf2tx-mm (P8) 7oct.24 加入多线程&#xff0c;分页OCR识别&#xff0c;提高性能与速度 使…

5G NR UE初始接入信令流程

文章目录 5G NR UE初始接入信令流程 5G NR UE初始接入信令流程 用户设备向gNB-DU发送RRCSetupRequest消息。gNB-DU 包含 RRC 消息&#xff0c;如果 UE 被接纳&#xff0c;则在 INITIAL UL RRC MESSAGE TRANSFER 消息中包括为 UE 分配的低层配置&#xff0c;并将其传输到 gNB-CU…

【OpenCV】基础操作学习--实现原理理解

读取和显示图像 基本操作 cv2.imread(filename , flags)&#xff1a;文件中读取图像&#xff0c;从指定路径中读取图像&#xff0c;返回一个图像数组&#xff08;NumPy数组&#xff09; filename&#xff1a;图像文件的路径flags&#xff1a;指定读取图像的方式 cv2.IMREAD_COL…

linux线程 | 线程的概念

前言:本篇讲述linux里面线程的相关概念。 线程在我们的教材中的定义通常是这样的——线程是进程的一个执行分支。 线程的执行粒度&#xff0c; 要比进程要细。 我们在读完这句话后其实并不能很好的理解什么是线程。 所以&#xff0c; 本节内容博主将会带友友们理解什么是线程&a…

代码随想录算法训练营第四十六天 | 647. 回文子串,516.最长回文子序列

四十六天打卡&#xff0c;今天用动态规划解决回文问题&#xff0c;回文问题需要用二维dp解决 647.回文子串 题目链接 解题思路 没做出来&#xff0c;布尔类型的dp[i][j]&#xff1a;表示区间范围[i,j] &#xff08;注意是左闭右闭&#xff09;的子串是否是回文子串&#xff0…

2024.10月7~10日 进一步完善《电信资费管理系统》

一、新增的模块&#xff1a; 在原项目基础上&#xff0c;新增加了以下功能&#xff1a; 1、增加AspectJ 框架的AOP 异常记录和事务管理模块。 2、增加SpringMVC的拦截器&#xff0c;实现登录 控制页面访问权限。 3、增加 Logback日志框架&#xff0c;记录日志。 4、增加动态验…

Hunuan-DiT代码阅读

一 整体架构 该模型是以SD为基础的文生图模型&#xff0c;具体扩散模型原理参考https://zhouyifan.net/2023/07/07/20230330-diffusion-model/&#xff0c;代码地址https://github.com/Tencent/HunyuanDiT&#xff0c;这里介绍 Full-parameter Training 二 输入数据处理 这里…

netdata保姆级面板介绍

netdata保姆级面板介绍 基本介绍部署流程下载安装指令选择设置KSM为什么要启用 KSM&#xff1f;如何启用 KSM&#xff1f;验证 KSM 是否启用注意事项 检查端口启动状态 netdata和grafana的区别NetdataGrafananetdata各指标介绍总览system overview栏仪表盘1. CPU2. Load3. Disk…

3.使用条件语句编写存储过程(3/10)

引言 在现代数据库管理系统中&#xff0c;存储过程扮演着至关重要的角色。它们是一组为了执行特定任务而编写的SQL语句&#xff0c;这些语句被保存在数据库中&#xff0c;可以被重复调用。存储过程不仅可以提高数据库操作的效率&#xff0c;还可以增强数据的安全性和一致性。此…

RPA技术的定义与原理

RPA&#xff08;Robotic Process Automation&#xff09;即机器人流程自动化&#xff0c;是一种利用软件机器人或机器人工具来自动执行重复性、规则性和可预测性的业务流程的技术。以下是对RPA技术的详细介绍&#xff1a; 一、RPA技术的定义与原理 RPA技术通过模拟人工操作&a…

【redis-06】redis的stream流实现消息中间件

redis系列整体栏目 内容链接地址【一】redis基本数据类型和使用场景https://zhenghuisheng.blog.csdn.net/article/details/142406325【二】redis的持久化机制和原理https://zhenghuisheng.blog.csdn.net/article/details/142441756【三】redis缓存穿透、缓存击穿、缓存雪崩htt…

关于Linux查看系统及版本信息的命令lsb_release命令以及Centos7中将redis服务写入systemctl服务

一、关于Linux查看系统及版本信息的命令lsb_release命令 linux查看系统是centos还是ubuntu&#xff0c;之前一直使用uname -a以及cat /etc/issue。但在某个服务器上发些这些都不行。有一个更好用的命令&#xff1a;lsb_release -a。如执行时提示-bash: lsb_release: 未找到命令…

Vscode+Pycharm+Vue.js+WEUI+django火锅(三)理解Vue

新创建的Vue项目里面很多文件&#xff0c;对于新手&#xff0c;老老实实做一下了解。 1.框架逻辑 框架的逻辑都是相通的&#xff0c;花点时间理一下就清晰了。 2.文件目录及文件 创建好的vue项目下&#xff0c;主要的文件和文件夹要先认识一下&#xff0c;并与框架逻辑对应起…

计算机毕业设计 校内跑腿业务系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…