C++二分查找算法的应用:俄罗斯套娃信封问题

本文涉及的基础知识点

二分查找

题目

给你一个二维整数数组 envelopes ,其中 envelopes[i] = [wi, hi] ,表示第 i 个信封的宽度和高度。

当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。

请计算 最多能有多少个 信封能组成一组"俄罗斯套娃"信封(即可以把一个信封放到另一个信封里面)。

注意:不允许旋转信封。

示例 1:

输入:envelopes = [[5,4],[6,4],[6,7],[2,3]]

输出:3

解释:最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。

示例 2:

输入:envelopes = [[1,1],[1,1],[1,1]]

输出:1
参数提示

1 <= envelopes.length <= 105

envelopes[i].length == 2

1 <= wi, hi <= 105

超时解法

有两个地方可能超时:

一,std::map<int, int> dp = mPreYToNum;

二,for (; (ij != dp.end()) && (ij->second > len); ++ij);

一处的时间复杂度是:O(n),最多有n个元素,所以总时间复杂度是O(n*n),会引起超时。

二处,总时间复杂度是O(n),最多删除n次,每个元素最多只会被删除一次。

代码

class Solution {

public:

int maxEnvelopes(vector<vector>& envelopes) {

std::map<int, vector> mXToYS;

for (const auto& v : envelopes)

{

mXToYS[v[0]].emplace_back(v[1]);

}

std::map<int, int> mPreYToNum;//y值对应最大数量,y值越大,对应的数量越大,否则被淘汰了

int iMax = 0;

for (const auto& it : mXToYS)

{

std::map<int, int> dp = mPreYToNum;

for (const auto& y : it.second)

{

int len = 0;

{//计算长度

const auto it = mPreYToNum.lower_bound(y);

len = 1 + ((mPreYToNum.begin() == it) ? 0 : std::prev(it)->second);

iMax = max(iMax, len);

}

{

const auto it = dp.lower_bound(y);

auto ij = it;

for (; (ij != dp.end()) && (ij->second > len); ++ij);

dp.erase(it, ij);

if (!dp.count(y))

{

dp[y] = len;

}

}

}

mPreYToNum.swap(dp);

}

	return iMax;
}

};

测试用例

template

void Assert(const T& t1, const T& t2)

{

assert(t1 == t2);

}

template

void Assert(const vector& v1, const vector& v2)

{

if (v1.size() != v2.size())

{

assert(false);

return;

}

for (int i = 0; i < v1.size(); i++)

{

Assert(v1[i] ,v2[i]);

}

}

int main()

{

Solution slu;

vector<vector> envelopes;

int res = 0;

envelopes = { {5,4},{6,4},{6,7},{2,3} };

res = slu.maxEnvelopes(envelopes);

Assert(res, 3);

envelopes = { {1,1},{1,1},{1,1} };

res = slu.maxEnvelopes(envelopes);

Assert(res, 1);

envelopes = { {1,1},{2,2},{2,3} };

res = slu.maxEnvelopes(envelopes);

Assert(res, 2);

envelopes = { {1,2},{2,3},{3,4},{3,5},{4,5},{5,5},{5,6},{6,7},{7,8} };

res = slu.maxEnvelopes(envelopes);

Assert(res, 7);

//CConsole::Out(res);

}

正确解法

变量含义

mXToYS key为envelopes的x,值为envelopes的y
mYToNum [x取[0,x), y对应最大套娃数量
vector<pair<int, int>> vYNum 当前x,各y对应数量

注意:

x相同,无法套娃,所以必须等当前x处理完毕,才能更新mYToNum。

y值越大,对应的数量越大,否则被淘汰了。所以mYToNum的键和值都是升序。

y小于当前y的,不会淘汰当前y,因为当前长度就是小于y的最大长度+1。

所以只会被相等的y淘汰。

当前y 可能淘汰比当前y大的。

代码

class Solution {

public:

int maxEnvelopes(vector<vector>& envelopes) {

std::map<int, vector> mXToYS;

for (const auto& v : envelopes)

{

mXToYS[v[0]].emplace_back(v[1]);

}

std::map<int, int> mYToNum;//y值对应最大数量

int iMax = 0;

for (const auto& it : mXToYS)

{

vector<pair<int, int>> vYNum;

for (const auto& y : it.second)

{

const auto it = mYToNum.lower_bound(y);

const int num = 1 + ((mYToNum.begin() == it) ? 0 : std::prev(it)->second);

iMax = max(iMax, num);

vYNum.emplace_back(y, num);

}

for(const auto[y,num]: vYNum)

{

const auto it = mYToNum.lower_bound(y);

auto ij = it;

for (; (ij != mYToNum.end()) && (ij->second <= num); ++ij);

mYToNum.erase(it, ij);

if (!mYToNum.count(y))

{

mYToNum[y] = num;

}

}

}

return iMax;

}

};

2023年1月旧代码

class Solution {

public:

int maxEnvelopes(vector<vector>& envelopes) {

std::map<int, vector> mWidthToHeights;

for (const auto& v : envelopes)

{

mWidthToHeights[v[0]].push_back(v[1]);

}

int iMax = 1;

std::map<int, int> mHeightNum;

for ( auto& it : mWidthToHeights)

{

sort(it.second.begin(), it.second.end(),std::greater());

for (auto& height : it.second)

{

auto it = mHeightNum.lower_bound(height);

int iNum =1;

if (mHeightNum.begin() != it)

{//没有套

auto ij = it;

--ij;

iNum = ij->second + 1;

}

iNum = max(iNum,mHeightNum[height]);

auto ij = it;

while ( (ij != mHeightNum.end())&& ( ij->second < iNum))

{

ij++;

}

mHeightNum.erase(it, ij);

mHeightNum[height] = max(mHeightNum[height], iNum);

iMax = max(iMax, mHeightNum[height]);

}

}

return iMax;

}

};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《闻缺陷则喜算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

充满正能量得对大家说
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
墨家名称的来源:有所得以墨记之。
算法终将统治宇宙,而我们统治算法。《喜缺全书》

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开

发环境: VS2022 C++17

相关推荐
以后不吃煲仔饭2 分钟前
Java基础夯实——2.7 线程上下文切换
java·开发语言
进阶的架构师3 分钟前
2024年Java面试题及答案整理(1000+面试题附答案解析)
java·开发语言
前端拾光者7 分钟前
利用D3.js实现数据可视化的简单示例
开发语言·javascript·信息可视化
The_Ticker8 分钟前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
程序猿阿伟9 分钟前
《C++ 实现区块链:区块时间戳的存储与验证机制解析》
开发语言·c++·区块链
傻啦嘿哟27 分钟前
如何使用 Python 开发一个简单的文本数据转换为 Excel 工具
开发语言·python·excel
大数据编程之光31 分钟前
Flink Standalone集群模式安装部署全攻略
java·大数据·开发语言·面试·flink
初九之潜龙勿用31 分钟前
C#校验画布签名图片是否为空白
开发语言·ui·c#·.net
爪哇学长44 分钟前
双指针算法详解:原理、应用场景及代码示例
java·数据结构·算法
爱摸鱼的孔乙己1 小时前
【数据结构】链表(leetcode)
c语言·数据结构·c++·链表·csdn