C++二分查找算法:有序矩阵中的第 k 个最小数组和

本文涉及的基础知识点

二分查找算法合集

本题的简化

C++二分查找算法:查找和最小的 K 对数字 十分接近m恒等于2

题目

给你一个 m * n 的矩阵 mat,以及一个整数 k ,矩阵中的每一行都以非递减的顺序排列。
你可以从每一行中选出 1 个元素形成一个数组。返回所有可能数组中的第 k 个 最小 数组和。
示例 1:
输入:mat = [[1,3,11],[2,4,6]], k = 5
输出:7
解释:从每一行中选出一个元素,前 k 个和最小的数组分别是:
[1,2], [1,4], [3,2], [3,4], [1,6]。其中第 5 个的和是 7 。
示例 2:
输入:mat = [[1,3,11],[2,4,6]], k = 9
输出:17
示例 3:
输入:mat = [[1,10,10],[1,4,5],[2,3,6]], k = 7
输出:9
解释:从每一行中选出一个元素,前 k 个和最小的数组分别是:
[1,1,2], [1,1,3], [1,4,2], [1,4,3], [1,1,6], [1,5,2], [1,5,3]。其中第 7 个的和是 9 。
示例 4:
输入:mat = [[1,1,10],[2,2,9]], k = 7
输出:12
参数范围
m == mat.length
n == mat.length[i]
1 <= m, n <= 40
1 <= k <= min(200, n ^ m)
1 <= mat[i][j] <= 5000
mat[i] 是一个非递减数组

分析

时间复杂度

O(mlog(500040)n+mkn)。GetLessKSum被调用m次,GetLessEqualSumNum共被调用mlog(500040)次。每次调用GetLessEqualSumNum,for循环共执行m次。
vRet.emplace_back极端情况下,可能被执行k
n次。

主要函数介绍

GetLessKSum两行升序数据的最小k个和
GetLessEqualSumNum两行升序数据和小于等于iSum的组合数量

注意:nums[i]为正数,所以如果pre的数量大于k,只需要保留前k小,其它的被淘汰了。

二分

寻找第一个符合条件的iSum,条件如下:
和小于等于iSum的组合数量大于等于k。

代码

核心代码

class Solution {
public:int kthSmallest(vector<vector<int>>& mat, int k) {m_c = mat.front().size();m_iK = k;vector<int> pre = mat[0];for (int r = 1; r < mat.size(); r++){pre = GetLessKSum(pre, mat[r]);}return pre.back();}vector<int> GetLessKSum(const vector<int>& pre, const vector<int>& cur){int left = 0, right = 5000 * 40;while (right - left > 1){const auto mid = left + (right - left) / 2;if (GetLessEqualSumNum(pre, cur, mid)>= m_iK){right = mid;}else{left = mid;}}vector<int> vRet;for (const auto& pr : pre){for (const auto& cu : cur){if (pr + cu <= right){vRet.emplace_back(pr + cu);}else{break;}}}sort(vRet.begin(), vRet.end());if (vRet.size() > m_iK){vRet.erase(vRet.begin() + m_iK, vRet.end());}return vRet;}int GetLessEqualSumNum(const vector<int>& pre, const vector<int>& cur,int iSum){int iNum = 0;for (const auto& pr : pre){iNum += std::upper_bound(cur.begin(), cur.end(), iSum - pr)- cur.begin();}return iNum;}int m_iK;int m_c;
};

测试用例

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()
{
vector<vector> mat;
int k;
int res;
{
Solution slu;
mat = { {1,3,11},{2,4,6} };
k = 5;
res = slu.kthSmallest(mat, k);
Assert(7, res);
}
{
Solution slu;
mat = { {1,3,11},{2,4,6} };
k = 9;
res = slu.kthSmallest(mat, k);
Assert(17, res);
}
{
Solution slu;
mat = { {1,10,10},{1,4,5},{2,3,6} };
k = 7;
res = slu.kthSmallest(mat, k);
Assert(9, res);
}
{
Solution slu;
mat = { {1,1,10},{2,2,9} };
k = 7;
res = slu.kthSmallest(mat, k);
Assert(12, res);
}

//CConsole::Out(res);

}

优化增加结果

vector<int> vRet;for (const auto& pr : pre){for (const auto& cu : cur){if (pr + cu < right){vRet.emplace_back(pr + cu);}else{break;}}}while (vRet.size() < m_iK){vRet.emplace_back(right);}

和小于right的数量<=k,如果不足够,则补right。时间复杂度由O(nk)降低到O(k+n)。

直接使用封装类

namespace NBinarySearch
{template<class INDEX_TYPE,class _Pr>INDEX_TYPE FindFrist(INDEX_TYPE left, INDEX_TYPE right, _Pr pr){while (right - left > 1){const auto mid = left + (right - left) / 2;if (pr(mid)){right = mid;}else{left = mid;}}return right;}
}class Solution {
public:int kthSmallest(vector<vector<int>>& mat, int k) {m_c = mat.front().size();m_iK = k;vector<int> pre = mat[0];for (int r = 1; r < mat.size(); r++){pre = GetLessKSum(pre, mat[r]);}return pre.back();}vector<int> GetLessKSum(const vector<int>& pre, const vector<int>& cur){auto GetLessEqualSumNum = [&pre, &cur, this](const int iSum)-> bool{int iNum = 0;for (const auto& pr : pre){iNum += std::upper_bound(cur.begin(), cur.end(), iSum - pr) - cur.begin();}return iNum >= m_iK;};const int right = NBinarySearch::FindFrist(0, 5000 * 40, GetLessEqualSumNum);		vector<int> vRet;for (const auto& pr : pre){for (const auto& cu : cur){if (pr + cu < right){vRet.emplace_back(pr + cu);}else{break;}}}while (vRet.size() < m_iK){vRet.emplace_back(right);}sort(vRet.begin(), vRet.end());if (vRet.size() > m_iK){vRet.erase(vRet.begin() + m_iK, vRet.end());}return vRet;}int GetLessEqualSumNum(const vector<int>& pre, const vector<int>& cur,int iSum){int iNum = 0;for (const auto& pr : pre){iNum += std::upper_bound(cur.begin(), cur.end(), iSum - pr)- cur.begin();}return iNum;}int m_iK;int m_c;
};

2023年3月暴力版

直接保留前k个。时间复杂度:O(mknlogk)
class Solution {
public:
int kthSmallest(vector<vector>& mat, int k) {
m_r = mat.size();
m_c = mat[0].size();
std::priority_queue pre;
pre.push(0);
for (int r = 0; r < mat.size(); r++)
{
std::priority_queue dp;
while (pre.size())
{
int t = pre.top();
pre.pop();
for (int c = 0; c < m_c; c++)
{
dp.push(mat[r][c] + t);
if (dp.size() > k)
{
dp.pop();
}
}
}
pre.swap(dp);
}
return pre.top();
}
int m_r, m_c;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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

本文涉及的基础知识点

C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频

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

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

相关文章

哈希unordered_set,unordered_map的练习

349. 两个数组的交集 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 输出&#xff1a;[2]示例 2&#xff1a; 输…

JSP过滤器和监听器

什么是过滤器 Servlet过滤器与Servlet十分相似&#xff0c;但它具有拦截客户端&#xff08;浏览器&#xff09;请求的功能&#xff0c;Servlet过滤器可以改变请求中的内容&#xff0c;来满足实际开发中的需要。 对于程序开发人员而言&#xff0c;过滤器实质就是在Web应用服务器…

使用Wireshark提取流量中图片方法

0.前言 记得一次CTF当中有一题是给了一个pcapng格式的流量包&#xff0c;flag好像在某个响应中的图片里。比较简单&#xff0c;后来也遇到过类似的情况&#xff0c;所以总结和记录一下使用Wireshark提取图片的方法。 提取的前提是HTTP协议&#xff0c;至于HTTPS的协议需要导入服…

【算法】摩尔投票算法

目录 1.概述2.算法思想3.代码实现3.1.t ⌊n / 2⌋3.2.t ⌊n / 3⌋3.3.t ⌊n / (m 1)⌋ 4.应用 参考&#xff1a;LeetCode_多数元素 II 题解 1.概述 &#xff08;1&#xff09;摩尔投票法 (Boyer–Moore Majority Vote Algorithm) 是一种用来寻找一组元素中多数元素的常量级…

flutter,uni-app开发调试ios

一、申请ios开发者账号 二、ios开发者配置 ios 开发者需要配置的地方 https://developer.apple.com/account/resources/certificates/list Certificates&#xff08;证书&#xff09;: 作用&#xff1a; 证书用于对应用程序和开发者进行身份验证&#xff0c;确保安全性和可…

如何为您的企业选择合适的多因素认证?

在传统的网络安全架构中&#xff0c;重点在于防止非法入侵&#xff0c;例如防火墙、VPN 、堡垒机等安全设备的重心都在于防止用户违规访问企业资源&#xff0c;一旦合法用户的账号密码被入侵者拿到&#xff0c;就可以冒充合法用户访问企业资源&#xff0c;所有的安全设备形同虚…

springcloud超市管理系统源码

技术说明&#xff1a; jdk1.8&#xff0c;mysql5.7&#xff0c;idea&#xff0c;vscode springcloud springboot mybatis vue elementui mysql 功能介绍&#xff1a; 后台管理&#xff1a; 统计分析&#xff1a;查看用户&#xff0c;商品&#xff0c;销售数量&#xff1b;…

Mock 数据

1. Mock 数据的方式 2. json-server 实现 Mock 数据 项目中安装json-server npm i -D json-server准备一个json文件添加启动命令 //package.json"scripts": {"start": "craco start","build": "craco build","test&q…

简单聊聊加密和加签的关系与区别

大家好&#xff0c;我是G探险者。 平时我们在项目上一定都听过加密和加签&#xff0c;加密可能都好理解&#xff0c;知道它是保障的数据的机密性&#xff0c;那加签是为了保障啥勒&#xff1f;它和加密有啥区别&#xff1f; 带着这个疑问&#xff0c;我们就来聊聊二者的区别。…

SHEIN出口车钥匙扣REACH认证指南解析

钥匙扣的材料一般为金属、皮革、塑料、橡胶、木头等。此物精致小巧、造型千变万化是人们随身携带的日常用品。钥匙扣是挂在钥匙圈上的一种装饰物品。钥匙扣出口需要办理REACH认证。 一、什么是REACH认证&#xff1f; REACH认证是欧盟28个成员国对进入其市场的所有化学品,&…

centos7中通过minikube安装Kubernetes

minikube是一款开源的Kubernetes集群管理器&#xff0c;它可以帮助您在本地计算机上轻松部署和管理Kubernetes集群。以下是minikube的安装和使用步骤&#xff1a; 安装Docker&#xff1a;如果您还没有安装Docker&#xff0c;可以从Docker官方网站上下载并安装适合您操作系统的…

Android和iOS应用程序加固方法详解:混淆、加壳、数据加密、动态加载和数字签名实现

目录 Android和iOS应用程序加固方法详解&#xff1a;混淆、加壳、数据加密、动态加载和数字签名实现 APP 加固方式 iOS APP加固代码实现 打开要处理的IPA文件 设置签名使用的证书和描述文件 开始ios ipa重签名 APP 加固方式 iOSAPP 加固是优化 iOS安全性的一种方法&…

C#枚举的使用

在C#中经常会用到枚举&#xff0c;是比较常用的定义一组常量集合的数据类型。我们使用枚举可以更方便理解和阅读代码&#xff0c;增强代码可读性&#xff0c;也在某种程度上提升了编程逻辑和维度。 基本语法&#xff1a; enum MyEnum {Value1,Value2,Value3&#xff0c;//...…

CSS 实现文本框签名

<div class"textarea-prepend"><textarea rows"6" placeholder"请输入消息内容"></textarea></div>.textarea-prepend {position: relative;}.textarea-prepend textarea {width: 300px;}.textarea-prepend::before {ba…

UE4基础篇十三:物理

一、笔记记录 1.1 碰撞交互 阻挡会设置为阻挡的两个(或更多)Actor之间自然发生。但是,需要启用模拟生成命中事件(Simulation Generates Hit Events)才能执行事件命中 ,要两个都相互设置阻挡模式才会生成命中事件 将Actor设置为重叠往往看起来它们彼此忽略,如果没有生…

【陈老板赠书活动 - 18期】-如何成为架构师这几本书推荐给你

陈老老老板&#x1f9b8; &#x1f468;‍&#x1f4bb;本文专栏&#xff1a;赠书活动专栏&#xff08;为大家争取的福利&#xff0c;免费送书&#xff09; &#x1f468;‍&#x1f4bb;本文简述&#xff1a;生活就像海洋,只有意志坚强的人,才能到达彼岸。 &#x1f468;‍&am…

JavaScript基础—引入方式、注释和结束符、输入和输出、变量、常量、数据类型、检测数据类型、类型转换、综合案例—用户订单信息

版本说明 当前版本号[20231123]。 版本修改说明20231123初版 目录 文章目录 版本说明目录JavaScript 基础 - 第1天介绍引入方式内部方式外部形式 注释和结束符单行注释多行注释 结束符输入和输出输出输入 变量声明赋值变量初始化更新变量 关键字变量名命名规则 常量数据类型…

什么是指针碰撞

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一波电子书籍资料&#xff0c;包含《Effective Java中文版 第2版》《深入JAVA虚拟机》&#xff0c;《重构改善既有代码设计》&#xff0c;《MySQL高性能-第3版》&…

WorkPlus实现完全私有化部署,企业数据安全有保障

在这个信息化飞速发展的时代&#xff0c;企业正面临着越来越多的数据安全挑战。为了确保数据的安全性和隐私性&#xff0c;WorkPlus迎合市场需求&#xff0c;推出了完全私有化部署方案&#xff0c;为企业提供了全面、可靠的安全保障&#xff0c;成为企业移动办公的首选。 WorkP…

C#中的迭代器和分部类

目录 一、迭代器 1.示例源码 2.生成效果&#xff1a; 二、分部类 1.示例源码 2.生成效果 迭代器在集合类中经常使用&#xff0c;而分部类则提供了一种将一个类分成多个类的方法&#xff0c;这对于有大量代码的类非常实用。 一、迭代器 迭代器是可以返回相同类型的值的有…