【二分查找】3143. 正方形中的最多点数

本文涉及的基础知识点

C++二分查找

LeetCode3143. 正方形中的最多点数

给你一个二维数组 points 和一个字符串 s ,其中 points[i] 表示第 i 个点的坐标,s[i] 表示第 i 个点的 标签 。
如果一个正方形的中心在 (0, 0) ,所有边都平行于坐标轴,且正方形内 不 存在标签相同的两个点,那么我们称这个正方形是 合法 的。
请你返回 合法 正方形中可以包含的 最多 点数。
注意:
如果一个点位于正方形的边上或者在边以内,则认为该点位于正方形内。
正方形的边长可以为零。
示例 1:
在这里插入图片描述
输入:points = [[2,2],[-1,-2],[-4,4],[-3,1],[3,-3]], s = “abdca”
输出:2
解释:
边长为 4 的正方形包含两个点 points[0] 和 points[1] 。
示例 2:
在这里插入图片描述
输入:points = [[1,1],[-2,-2],[-2,2]], s = “abb”
输出:1
解释:
边长为 2 的正方形包含 1 个点 points[0] 。
示例 3:
输入:points = [[1,1],[-1,-1],[2,-2]], s = “ccd”
输出:0
解释:
任何正方形都无法只包含 points[0] 和 points[1] 中的一个点,所以合法正方形中都不包含任何点。
提示:
1 <= s.length, points.length <= 105
points[i].length == 2
-109 <= points[i][0], points[i][1] <= 109
s.length == points.length
points 中的点坐标互不相同。
s 只包含小写英文字母。

分析

性质一:某正方形包含点(x,y),则一定包含(-x,y)和(x,-y)。不包含类似。如果坐标是负数,改成绝对值,结果不变。
性质二通过性质一转换后。如果x<y,某正方形包含(x,y),则一定包含(y,y)。即正方形包含(x,y)等效与包含(y,y)。同理,x > y。包含(x,y),等效于包含(x,x)。两者结合,m= max(x,y),包含(x,y), 等效于包含(m,m)。正方形不包含(x,y)等效与不包含(m,m)。我们只需要记录各点的m。即雪切夫距离:两个点之间的距离定义是其各坐标数值差绝对值的最大值。
性质三:正方形包含(m,m)的充分必要条件是:edge >= m。
如果各标签都只有一个点,返回点的数量。否则求包括同一标签两个点或以上的最小正方形,令其变成为s。返回边长为s-1的正方形包含点的数量。

方法一:排序。

分治法:分别记录各标签的雪切夫距离,并按升序排序。x[i][1]的最小值就是s。

方法二:C++二分法

二分类型:寻找首端。
Check函数的参数范围:[1,109]。
Check函数:
任意x[i],大于等于mid的数量大于1,返回true。Check函数的时间复杂度:O(n),枚举所有点。总时间复杂度:O(nlogm),m = max(points)
所以标签都只有一个点,提前返回点的数量。故一定有解。否则,需要判断是否有解。

代码

核心代码

template<class INDEX_TYPE>
class CBinarySearch
{
public:
	CBinarySearch(INDEX_TYPE iMinIndex, INDEX_TYPE iMaxIndex):m_iMin(iMinIndex),m_iMax(iMaxIndex) {}
	template<class _Pr>
	INDEX_TYPE FindFrist( _Pr pr)
	{
		auto left = m_iMin - 1;
		auto rightInclue = m_iMax;
		while (rightInclue - left > 1)
		{
			const auto mid = left + (rightInclue - left) / 2;
			if (pr(mid))
			{
				rightInclue = mid;
			}
			else
			{
				left = mid;
			}
		}
		return rightInclue;
	}
	template<class _Pr>
	INDEX_TYPE FindEnd( _Pr pr)
	{
		int leftInclude = m_iMin;
		int right = m_iMax + 1;
		while (right - leftInclude > 1)
		{
			const auto mid = leftInclude + (right - leftInclude) / 2;
			if (pr(mid))
			{
				leftInclude = mid;
			}
			else
			{
				right = mid;
			}
		}
		return leftInclude;
	}
protected:
	const INDEX_TYPE m_iMin, m_iMax;
};

class Solution {
		public:
			int maxPointsInsideSquare(vector<vector<int>>& points, string s) {
				vector<int> ms[26];
				for (int i = 0; i < points.size(); i++) {
					ms[s[i] - 'a'].emplace_back(max(abs(points[i][0]), abs(points[i][1])));
				}
				auto Check = [&](int mid) {
					for (const auto& v : ms) {
						int cnt = 0;
						for (const auto& n : v) {
							cnt += (n <= mid);
						}
						if (cnt > 1) { return true; }
					}
					return false;
				};
				auto ret = CBinarySearch<int>(1, 1000'000'000).FindFrist(Check);
				if (!Check(ret)) { return s.length(); }
				int cnt = 0;
				for (const auto& v : ms) {					
					for (const auto& n : v) {
						cnt += (n < ret );
					}
				}
				return cnt;
			}
		};

单元测试

	vector<vector<int>> points;
		string s;
		TEST_METHOD(TestMethod11)
		{
			points = { {2,2},{-1,-2},{-4,4},{-3,1},{3,-3} }, s = "abdca";
			auto res = Solution().maxPointsInsideSquare(points, s);
			AssertEx(2, res);
		}
		TEST_METHOD(TestMethod12)
		{
			points = { {1,1},{-2,-2},{-2,2} }, s = "abb";
			auto res = Solution().maxPointsInsideSquare(points, s);
			AssertEx(1, res);
		}
		TEST_METHOD(TestMethod13)
		{
			points = { {1,1},{-1,-1},{2,-2} }, s = "ccd";
			auto res = Solution().maxPointsInsideSquare(points, s);
			AssertEx(0, res);
		}
		TEST_METHOD(TestMethod14)
		{
			points = { {16, 32}, { 27,3 }, { 23,-14 }, { -32,-16 }, { -3,26 }, { -14,33 }}, s = "aaabfc";
			auto res = Solution().maxPointsInsideSquare(points, s);
			AssertEx(2, res);
		}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

  • 162
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 143
    评论
评论 143
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闻缺陷则喜何志丹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值