【二分查找】自写二分函数的总结

news2024/11/29 7:51:12

作者推荐

【动态规划】【广度优先搜索】LeetCode:2617 网格图中最少访问的格子数

本文涉及的基础知识点

二分查找算法合集

自写二分函数 的封装

我暂时只发现两种:
一,在左闭右开的区间寻找最后一个符合条件的元素,我封装成FindEnd函数。
二,在左开右闭的区间寻找第一个符合条件的元素,我封装成FindFirst函数。

namespace NBinarySearch
{
	template<class INDEX_TYPE,class _Pr>
	INDEX_TYPE FindFrist(INDEX_TYPE left, INDEX_TYPE rightInclue, _Pr pr)
	{
		while (rightInclue - left > 1)
		{
			const auto mid = left + (rightInclue - left) / 2;
			if (pr(mid))
			{
				rightInclue = mid;
			}
			else
			{
				left = mid;
			}
		}
		return rightInclue;
	}

	template<class INDEX_TYPE, class _Pr>
	INDEX_TYPE FindEnd(INDEX_TYPE leftInclude, INDEX_TYPE right, _Pr pr)
	{
		while (right - leftInclude > 1)
		{
			const auto mid = leftInclude + (right - leftInclude) / 2;
			if (pr(mid))
			{
				leftInclude = mid;
			}
			else
			{
				right = mid;
			}
		}
		return leftInclude;
	}
}

左闭右开 左开右闭的例子

LeetCode33: C++算法:二分查找旋转数组

class Solution {
public:
	int search(vector<int>& nums, int target) {
		int rBegin = NBinarySearch::FindFrist(-1, (int)nums.size() - 1, [&](const int mid) {return nums[mid] <= nums.back(); });
		if (target <= nums.back())
		{
			return Find(nums, rBegin, nums.size(), target);
		}
		return Find(nums, 0, rBegin, target);
	}
	int Find(const vector<int>& nums, int left, int r, int target)
	{
		int iRet = NBinarySearch::FindEnd(left,r, [&](const int mid) {return nums[mid] <= target; });
		return (target == nums[iRet]) ? iRet : -1;
	}
};
int main()
{
	vector<int> vNums = { 1,2,3,4,6 };
	auto res = Solution().search(vNums, 4);
	std::cout << "index:" << res;
	if (-1 != res)
	{
		std::cout << " value:" << vNums[res];
	}
}

左闭右开的例子

Leetcode2790:C++二分查找算法的应用:长度递增组的最大数目

namespace NBinarySearch
{
	template<class INDEX_TYPE,class _Pr>
	INDEX_TYPE FindFrist(INDEX_TYPE left, INDEX_TYPE rightInclue, _Pr pr)
	{
		while (rightInclue - left > 1)
		{
			const auto mid = left + (rightInclue - left) / 2;
			if (pr(mid))
			{
				rightInclue = mid;
			}
			else
			{
				left = mid;
			}
		}
		return rightInclue;
	}

	template<class INDEX_TYPE, class _Pr>
	INDEX_TYPE FindEnd(INDEX_TYPE leftInclude, INDEX_TYPE right, _Pr pr)
	{
		while (right - leftInclude > 1)
		{
			const auto mid = leftInclude + (right - leftInclude) / 2;
			if (pr(mid))
			{
				leftInclude = mid;
			}
			else
			{
				right = mid;
			}
		}
		return leftInclude;
	}
}

class Solution {
public:
	int maxIncreasingGroups(vector<int>& usageLimits) {
		m_c = usageLimits.size();
		m_v = usageLimits;
		sort(m_v.begin(), m_v.end());
		auto Can = [&](int len)
		{
			int i = m_c - 1;
			long long llNeed = 0;
			for (; len > 0; len--, i--)
			{
				llNeed -= (m_v[i] - len);
				if (m_v[i] >= len)
				{
					llNeed = max(0LL, llNeed);
				}
			}
			for (; i >= 0; i--)
			{
				llNeed -= m_v[i];
			}
			return llNeed <= 0;
		};
		return NBinarySearch::FindEnd(1, m_c + 1, Can);
	}
	
	int m_c;
	vector<int> m_v;
};
template<class T>
void Assert(const T& t1, const T& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& 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<int> usageLimits;
	int res = 0;
	usageLimits = { 2,2,2 };
	res = slu.maxIncreasingGroups(usageLimits);
	Assert(res, 3);
	usageLimits = { 1,2,5 };
	res = slu.maxIncreasingGroups(usageLimits);
	Assert(res, 3);
	usageLimits = { 2,1,2 };
	res = slu.maxIncreasingGroups(usageLimits);
	Assert(res, 2);
	usageLimits = { 1,1 };
	res = slu.maxIncreasingGroups(usageLimits);
	Assert(res, 1);

	//CConsole::Out(res);
}

左闭右开的应用

C++二分查找算法的应用:最小好进制

Is

计算是否存在m位 k进制的1为目标数。m位iRet 进制1大于等于目标数,可能有多个符合的iRet,取最小值。非最小值一定不是。

namespace NBinarySearch
{
	template<class INDEX_TYPE,class _Pr>
	INDEX_TYPE FindFrist(INDEX_TYPE left, INDEX_TYPE rightInclue, _Pr pr)
	{
		while (rightInclue - left > 1)
		{
			const auto mid = left + (rightInclue - left) / 2;
			if (pr(mid))
			{
				rightInclue = mid;
			}
			else
			{
				left = mid;
			}
		}
		return rightInclue;
	}

	template<class INDEX_TYPE, class _Pr>
	INDEX_TYPE FindEnd(INDEX_TYPE leftInclude, INDEX_TYPE right, _Pr pr)
	{
		while (right - leftInclude > 1)
		{
			const auto mid = leftInclude + (right - leftInclude) / 2;
			if (pr(mid))
			{
				leftInclude = mid;
			}
			else
			{
				right = mid;
			}
		}
		return leftInclude;
	}
}

class Solution {
public:
	string smallestGoodBase(string n) {
		long long llN = 0;
		for (const auto& ch : n)
		{
			llN = (llN * 10 + ch - '0');
		}
		for (int i = 70; i > 2; i--)
		{
			long long llRet = Is(i, llN);
			if (llRet > 0)
			{
				return std::to_string(llRet);
			}
		}
		return std::to_string(llN - 1);
	}
	long long Is(int m, long long n)
	{
		int iRet = NBinarySearch::FindEnd(2LL, n + 1LL, [&](const auto mid) {return Cmp(mid, m, n) >= 0; });
		return (0 == Cmp(iRet,m,n))? iRet : 0;
	}
	//k进制的m个1和n的大小比较,n大返回正数,相等返回0,n小返回负数
	long long Cmp(long long k, int m, long long n)
	{
		long long llHas = 1;
		for (; m > 0; m--)
		{
			if (n < llHas)
			{
				return -1;
			}
			n -= llHas;
			if (m > 1)
			{// 最后一次llHas并不使用,所以越界不影响
				if (LLONG_MAX / k < llHas)
				{
					return -1;
				}
				llHas *= k;
			}
		}
		return n;
	}
};

template<class T>
void Assert(const T& t1, const T& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& 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;
	string res;
	res = slu.smallestGoodBase("470988884881403701");
	Assert(res, std::string("686286299"));
	res = slu.smallestGoodBase("2251799813685247");
	Assert(res, std::string("2"));
	res = slu.smallestGoodBase("13");
	Assert(res, std::string("3"));
	res = slu.smallestGoodBase("4681");
	Assert(res, std::string("8"));
	res = slu.smallestGoodBase("1000000000000000000");
	Assert(res, std::string("999999999999999999"));
	res = slu.smallestGoodBase("1333");
	Assert(res, std::string("36"));
	res = slu.smallestGoodBase("463381");
	Assert(res, std::string("463380"));

	//CConsole::Out(res);
}

扩展阅读

视频课程

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

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

相关文章

Automotive Bionics

汽车仿生学是一种通过模拟生物系统的某些特征来设计汽车的方法。一些典型的汽车仿生学例子包括&#xff1a; 鲨鱼式车型&#xff1a;这种车型的设计灵感来源于鲨鱼的流线型身体&#xff0c;这种设计能够减少空气阻力和水阻力&#xff0c;提高车辆的燃油效率和行驶速度。 甲壳虫…

JavaSE第7篇:封装

文章目录 一、封装1、好处:2、使用 二、四种权限修饰符三、构造器1、作用2、说明3、属性赋值的过程 一、封装 封装就是将类的属性私有化,提供公有的方法访问私有属性 不对外暴露打的私有的方法 单例模式 1、好处: 1.只能通过规定的方法来访问数据 2.隐藏类的实例细节,方便…

HarmonyOS云开发基础认证考试满分答案(100分)【全网最全-不断更新】【鸿蒙专栏-29】

系列文章&#xff1a; HarmonyOS应用开发者基础认证满分答案&#xff08;100分&#xff09; HarmonyOS应用开发者基础认证【闯关习题 满分答案】 HarmonyOS应用开发者高级认证满分答案&#xff08;100分&#xff09; HarmonyOS云开发基础认证满分答案&#xff08;100分&#xf…

DC-4靶场

目录 nmap进行主机发现 尝试反弹shell&#xff1a; 进入交互式shell&#xff1a; Hydra爆破jim用户密码&#xff1a; ssh登录charles &#xff1a; 提权&#xff08;三种方法&#xff09;&#xff1a; exim4提权…

数据高可用架构设计与实现

大型企业如何实现 MySQL 到 Redis 的同步 前面曾提到过 Read/Write Through 和 Cache Aside 这几种更新缓存的模式或者说策略&#xff0c;这几种策略都存在缓存不命中的可能性&#xff0c;如果缓存没有命中&#xff0c;就需要直接访问数据库以获取数据。—般情况下&#xff0c…

Ansible-playbook编译.yml脚本

1、playbook是什么&#xff1f; 在Ansible中&#xff0c;Playbook是用于配置、部署和管理被控节点的剧本。它由一个或多个play&#xff08;角色&#xff09;组成&#xff0c;每个play可以包含多个task&#xff08;台词&#xff0c;动作&#xff09;。使用Ansible的Playbook&am…

【Windows】windows11右键默认显示更多选项的办法

Windows11系统的右键菜单显示&#xff0c;需要多点一次“显示更多选项”才能看到所有菜单内容&#xff0c;按下面步骤简单设置一下就能恢复成Windows经典的右键菜单显示。 1. 2.输入命令【reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a…

JMESPath语言

JMESPath&#xff08;JSON Matching Expression Path&#xff09; 一种查询语言。 主要用于从JSON文档中检索和过滤数据。 通过写表达式提取和处理JSON数据&#xff0c;而无需编写复杂的代码。 功能&#xff1a;数据提取、过滤、转换、排序。 场景&#xff1a;处理API响应…

中文编程工具下载,编程工具构件之复选框构件

一、前言 零基础自学编程&#xff0c;中文编程工具下载&#xff0c;中文编程工具构件之扩展系统菜单构件教程 编程系统化教程链接https://jywxz.blog.csdn.net/article/details/134073098?spm1001.2014.3001.5502 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&a…

【案例】--“特别抢购”案例

目录 一、案例背景二、技术方案思路三、技术方案具体设计3.1、表设计3.2、Java代码实现一、案例背景 A公司向供应商B公司买了一套软件产品。B公司的这套产品有多个应用系统服务【如appId1、appId2、appId3】,每个应用都有各自的业务应用场景,但都需要管理文档,那么就需要磁…

C++:函数重载

1.函数重载概念 函数重载就是用同一个函数名定义的不同函数&#xff0c;当函数名和不同的参数搭配时函数的功能和含义不同。 2.实现函数重载的条件 同一个作用域&#xff0c;参数个数不同或者参数类型不同或者参数顺序不同(满足一个即可) void func(){} void func(int x){} v…

74hc244驱动数码管显示电路及程序

把七或八只发光二极管组合在一个模件上组成了个8字和小数点&#xff0c;用以显示数字。为了减少管脚&#xff0c;把各个发光管的其中同一个极接在一起作为共用点&#xff0c;因此就产生了共阳极和共阴极数码之说。共阳管就是把各个发光管的正极接在一起&#xff0c;而共阴管就刚…

web(HTML之表单练习)

使用HTML实现该界面&#xff1a; 要求如下&#xff1a; 用户名为文本框&#xff0c;名称为 UserName&#xff0c;长度为 15&#xff0c;最大字符数为 20。 密码为密码框&#xff0c;名称为 UserPass&#xff0c;长度为 15&#xff0c;最大字符数为 20。 性别为两个单选按钮&a…

PowerShell实战(一)PowerShell使用ImportExcel模块轻松操作Excel

目录 一、介绍 二、安装模块 三、操作示例 1、导出excel 2、读取Excel数据 3、导出包含图表的Excel 4、导出包含汇总列和图表的Excel 一、介绍 ImportExcel模块可以理解为基于PowerShell环境操作Excel的强大类库&#xff0c;使用它可以在 Windows、Linux 和 Mac 上都可以使用。…

天选姬·桌宠 你值得拥有

天选姬桌宠 简介官网地址安装教程1.获取方式2.安装3.功能效果4.桌宠互动5.下载地址 彩蛋搜狗输入法天选姬主题天选姬桌宠视频简介天选姬静态壁纸天选姬动态壁纸 天选姬桌宠 简介 互动类虚拟桌面宠物&#xff0c;让你的桌面变得有趣和精彩。 官网地址 载中心 | 官方支持 | A…

浏览器的事件循环机制(Event loop)

事件循环 浏览器的进程模型 何为进程&#xff1f; 程序运行需要有它自己专属的内存空间&#xff0c;可以把这块内存空间简单的理解为进程 每个应用至少有一个进程&#xff0c;进程之间相互独立&#xff0c;即使要通信&#xff0c;也需要双方同意。 何为线程&#xff1f; …

PyQt6 QScrollBar滚动条控件

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计48条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

VRRP(虚拟路由冗余协议)

一.VRRP简介 1.VRRP是什么 Virtual route Redundancy Protocol&#xff0c;也叫虚拟路由器冗余协议。 利用VRRP&#xff0c;一组路由器协同工作&#xff0c;单只有一个处于Master状态&#xff0c;处于该状态的路由器&#xff08;的接口&#xff09;承担实际的数据流量转发任…

day39算法训练|动态规划part02

62.不同路径 代码随想录 按照动规五部曲来分析&#xff1a; 1确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][j] &#xff1a;表示从&#xff08;0 &#xff0c;0&#xff09;出发&#xff0c;到(i, j) 有dp[i][j]条不同的路径。 2确定递推公式 想要求…

[c++]—vector类___提升版(带你了解vector底层的运用)

我写我 不论主谓宾 可以反复错 &#x1f308;vector的介绍 1.vector是表示可变大小数组的序列容器2.就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素&#xff0c;也就是意味着可以采用下标对vector的元素进行访问&#xff0c;和数组一样高效。但是又不像数组&…