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

news2024/11/14 2:31:37

本文涉及的基础知识点

二分查找算法合集

本题的简化

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.coloradmin.cn/o/1228699.html

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

相关文章

庖丁解牛:NIO核心概念与机制详解 04 _ 分散和聚集

文章目录 Pre概述分散/聚集 I/O分散/聚集的应用聚集写入Code Pre 庖丁解牛&#xff1a;NIO核心概念与机制详解 01 庖丁解牛&#xff1a;NIO核心概念与机制详解 02 _ 缓冲区的细节实现 庖丁解牛&#xff1a;NIO核心概念与机制详解 03 _ 缓冲区分配、包装和分片 概述 分散/聚…

学霸教你自学人工智能

在这个信息爆炸的时代&#xff0c;人工智能已经渗透到我们生活的方方面面。无论是语音助手、自动驾驶汽车&#xff0c;还是医疗诊断&#xff0c;人工智能都在发挥着越来越重要的作用。如果你对人工智能充满热情&#xff0c;希望在这个领域有所建树&#xff0c;那么&#xff0c;…

鸿蒙:使用Stack、ContentTable、Flex等组件和布局实现一个显示界面

效果展示 一.概述 跟随官网继续HarmonyOS学习 本篇博文实现一个食物详情页的开发Demo 通过这个开发过程学习如何使用容器组件Stack、Flex和基本组件Image、Text&#xff0c;构建用户自定义组件&#xff0c;完成图文并茂的食物介绍 二.构建Stack布局 1.食物名称 创建Stack…

STM32CubeMX学习笔记-CAN接口使用

STM32CubeMX学习笔记-CAN接口使用 CAN总线传输协议1.CAN 总线传输特点2.位时序和波特率3.帧的种类4.标准格式数据帧和遥控帧从STM32F407参考手册中可以看出主要特性如下CAN模块基本控制函数CAN模块消息发送CAN模块消息接收标识符筛选发送中断的事件源和回调函数 CubeMX项目设置…

解决SLF4J: Class path contains multiple SLF4J bindings.

这个问题在使用Dubbo时产生&#xff0c;推荐一个插件Maven Helper 1.插件安装 安装好后下方会有一个Dependency Analyzer&#xff0c;点击进入 2.删除冲突项 根据报错信息选择一个slf4j删除&#xff0c;不一定是slf4j-log4j12&#xff0c;每个人的报错信息不一样&#xff0c;图…

FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(3)

FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法&#xff08;3&#xff09; 工程目的IIC时序图IIC 读写操作方法汇总正点原子IIC实验工程整体框图和模块功能简介&#xff0c;如表下图所示&#xff1a; IIC 驱动模块设计时钟规划状态跳转流程单次写操作的波形图如下图所示&…

Linux socket编程(4):服务端fork之僵尸进程的处理

在上一节利用fork实现服务端与多个客户端建立连接中&#xff0c;我们使用fork函数来实现服务端既可以accept新的客户端连接请求&#xff0c;又可以接收已连接上的客户端发来的消息。但在Linux中&#xff0c;在子进程终止后&#xff0c;父进程需要处理该子进程的终止状&#xff…

LeetCode(29)三数之和【双指针】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 三数之和 1.题目 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复…

RE2文本匹配实战

引言 今天我们来实现RE2进行文本匹配&#xff0c;模型实现参考了官方代码https://github.com/alibaba-edu/simple-effective-text-matching-pytorch。 模型实现 RE2模型架构如上图所示。它的输入是两个文本片段&#xff0c;所有组件参数除了预测层和对齐层外都是共享的。上图…

计算机网络期末复习(知识点)

一、计算机网络体系结构 计算机网络&因特网&#xff1a; 计算机网络定义&#xff1a;将地理位置不同的具有独立功能的多台计算机及其外部设备&#xff0c;通过通信线路连接起来&#xff0c;在网络操作系统&#xff0c;网络关联软件及网络协议的管理和协调下&#xff0c;实…

在 Linux 上搭建 Java Web 项目环境(最简单的进行搭建)

要在 Linux 上安装的程序有 1.JDK (要想运行 java 程序 JDK 是必不可少的) 2.Tomcat &#xff08;HTTP 服务器&#xff0c;是管理 Web 项目的常用工具&#xff09; 3. mysql &#xff08;数据库&#xff09; 一.安装 JDK 博主使用的 Linux 发行版是 centos &#xff0c;cen…

kubenetes-服务发现和负载均衡

一、服务发布 kubenetes把服务发布至集群内部或者外部&#xff0c;服务的三种不同类型&#xff1a; ClusterlPNodePortLoadBalancer ClusterIP是发布至集群内部的一个虚拟IP,通过负载均衡技术转发到不同的pod中。 NodePort解决的是集群外部访问的问题&#xff0c;用户可能不…

【MySQL--->事务】

文章目录 [TOC](文章目录) 一、基本概念二、事务的操作1.设置全局事务隔离级别2.设置事务提交方式3.事务操作 三、事务隔离性1.隔离性概念2 .隔离级别设置 四、MVCC多版本控制2. read view 一、基本概念 事务是由若干条具有逻辑相关性的SQL语句组成的,用来完成某种任务的**逻辑…

java“俄罗斯方块”

首先新建议一个包为Tetris &#xff08;俄罗斯方块&#xff09; 类名也叫做Tetris&#xff1b; 代码运行&#xff1a; package Tetris; import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridLayout; import java.awt.event.KeyEvent; import java.aw…

【运维篇】Redis常见运维命令详解

文章目录 1. 前言2. 连接管理命令详解2.1 AUTH命令2.2 PING命令2.3 SELECT命令2.4 QUIT命令 3. 服务器管理命令详解3.1 FLUSHALL命令3.2 SAVE/BGSAVE命令3.3 SHUTDOWN命令 4. 安全管理命令详解4.1 CONFIG命令4.1.1 CONFIG SET命令用法4.1.2 CONFIG GET命令用法 4.2 AUTH命令 5.…

开源更安全? yum源配置/rpm 什么是SSH?

文章目录 1.开放源码有利于系统安全2.yum源配置&#xff0c;这一篇就够了&#xff01;(包括本地&#xff0c;网络&#xff0c;本地共享yum源)3.rpm包是什么4.SSH是什么意思&#xff1f;有什么功能&#xff1f; 1.开放源码有利于系统安全 开放源码有利于系统安全 2.yum源配置…

代码随想录刷题】Day16 二叉树

文章目录 1.【104】二叉树的最大深度&#xff08;优先掌握递归&#xff09;1.1 题目描述1.2 java代码实现 2.【111】二叉树的最小深度&#xff08;优先掌握递归&#xff09;2.1 题目描述2.2 java代码实现 3.【222】完全二叉树的节点个数3.1 题目描述3.2 java代码实现 【104】二…

6 Redis的慢查询配置

1、redis的命令执行流程 redis的慢查询只针对步骤3 默认情况下&#xff0c;慢查询的阈值是10ms 在配置文件中进行配置 //这个参数的单位为微秒 //如果将这个值设置为负数&#xff0c;则会禁用慢日志功能 //如果将其设置为0&#xff0c;则会强制记录每个命令 slowlog-log-slow…

Java21新增特性

版本介绍 Java 21是Java平台的一个新版本&#xff0c;于2023年9月19日由Oracle公司正式发布。这个版本包含了数千个性能、稳定性和安全性更新&#xff0c;以及几十个新功能和增强。其中&#xff0c;15个增强被赋予了自己的JDK增强提案&#xff08;JEP&#xff09;&#xff0c;…

回归预测 | Matlab实现HPO-ELM猎食者算法优化极限学习机的数据回归预测

回归预测 | Matlab实现HPO-ELM猎食者算法优化极限学习机的数据回归预测 目录 回归预测 | Matlab实现HPO-ELM猎食者算法优化极限学习机的数据回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现HPO-ELM猎食者算法优化极限学习机的数据回归预测&#xff08;…