C++二分查找算法的应用:最长递增子序列

涉及知识点

二分查找 单调映射

源码下载

点击下载源码

题目

给你一个整数数组 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 <= numsi <=104

暴力解法

分析

m_vReti,记录以numsi结尾的最长严格递增系列。计算m_vReti的方法:numsj < numsi中最大m_vRetj+1。如果不存在合法的j,则m_vReti等于1。

下表以{1,2,6,5,4,5}

|---|---------------------------------------|-------------|
| i | m_vRet0,i),加粗表示nums\[j<numsi | m_vReti |
| 0 | | 1 |
| 1 | 1 | 2{1,2} |
| 2 | 1 2 | 3{1,2,6} |
| 3 | 1 23 | 3{1,2,5} |
| 4 | 1 23 3 | 3{1,2,4} |
| 5 | 1 2 3 3 3 | 4{1,2,4,5} |

两层循环,分别枚举i和j,故总时间复杂度是O(n2)。

代码

class Solution {

public:

int lengthOfLIS(vector<int>& nums) {

m_c = nums.size();

m_vRet.resize(m_c);

for (int i = 0; i < m_c; i++)

{

int iPreLen = 0;

for (int j = 0; j < i; j++)

{

if (numsj >= numsi)

{

continue;

}

iPreLen = max(iPreLen, m_vRetj);

}

m_vReti = iPreLen + 1;

}

return *std::max_element(m_vRet.begin(), m_vRet.end());

}

vector<int> m_vRet;

int m_c;

};

有序映射

分析

如果numsj1 > numsj2,且m_vRetj1 <= m_vRetj2,那么j1被j2淘汰。以numsj为key,m_vRetj为值,创建有序映射。key和value都是升序。

下表以{1,2,6,5,4,5,5}为列来说明,加粗表示新增加,删除线表示删除。

|------------------------------|
| {1,1} |
| {1,1},{2,2} |
| {1,1},{2,2},{6,3} |
| {1,1},{2,2},{5,3} ,{6,3} |
| {1,1},{2,2},{4,3} ,{5,3} |
| {1,1},{2,2},{4,3},{5,4} |
| {1,1},{2,2},{4,3},{5,4} |

代码

class Solution {

public:

int lengthOfLIS(vector<int>& nums) {

m_c = nums.size();

m_vRet.resize(m_c);

std::map<int, int> mValueLen = { {-1000 * 1000,0} };

for (int i = 0; i < m_c; i++)

{

//计算以numsi结尾的最长长度

auto it = mValueLen.lower_bound(numsi);

const int iLen = std::prev(it)->second + 1;

m_vReti = iLen;

//如果numsj >= numsj,且长度小于等于删除

auto ij = it;

for (; (ij != mValueLen.end()) && (ij->second <= iLen); ++ij);

mValueLen.erase(it, ij);

//如果numsi存在,说明旧值比当前值大,不能处理

if (!mValueLen.count(numsi))

{

mValueLennums\[i] = iLen;

}

}

return *std::max_element(m_vRet.begin(), m_vRet.end());

}

vector<int> m_vRet;

int m_c;

};

其它

学院课程

|---------------------------------------------------------------------------------------------------------------------------------|
| 基础算法的C++实现课程,请点击下面的CSDN学院的链接。讲义有算法详解。 |
| 2024年1月15之前完全免费,之后绝大部分免费 |
| https://edu.csdn.net/course/detail/38771 |
| C#入职培训 |
| 此课程的目的:让新同事更快完成从学生到C#程序员的转换,更快上手完成C#的开发工作。 |
| https://edu.csdn.net/course/detail/38768 |
| C++入职培训 |
| 让新同事更快完成从学生到C++程序员的转换,更快上手完成C++的开发工作。 |
| https://edu.csdn.net/course/detail/32049 |

运行验证环境

Win10 VS2022 Ck++17 或win7 VS2019 C++17

每天都补充正能量

|---------------|
| 好好学习,天天向上。 |
| 事无终始,无务多业。 |
| 是故置本不安者,无务丰末。 |

相关下载

如果你时间宝贵,只想看精华,请到CSDN下载频道下载《闻缺陷则喜算法册》doc版

https://download.csdn.net/download/he_zhidan/88348653

相关推荐
Navigator_Z10 小时前
LeetCode //C - 1089. Duplicate Zeros
c语言·算法·leetcode
cany100010 小时前
C++ -- 可变参数模板
c++
不会C语言的男孩11 小时前
C++ Primer 第2章:变量和基本类型
开发语言·c++
云泽80813 小时前
C++ 可调用对象通关指南:深度解析 Lambda 表达式、function 包装器与 bind 绑定器
开发语言·c++·算法
wlsh1513 小时前
Go 迭代器
算法
Tri_Function13 小时前
简单图论大学习
c++
语戚13 小时前
力扣 3161. 块放置查询:线段树解法(Java 实现)
java·算法·leetcode·面试·线段树·力扣·
lqqjuly14 小时前
C++ 完整知识体系—从基础语法到现代 C++23 的系统性总结
c++·c++23
CS创新实验室14 小时前
从顺序表到动态数组:数据结构的永恒基石与现代语言的优雅封装
数据结构·算法
王老师青少年编程14 小时前
信奥赛C++提高组csp-s之FHQ Treap
c++·csp·平衡树·信奥赛·csp-s·提高组·fhq treap