【键值皆有序map 线段树 数学 】100240. 最小化曼哈顿距离

本文涉及知识点

键值皆有序map 线段树 数学

LeetCode100240. 最小化曼哈顿距离

给你一个下标从 0 开始的数组 points ,它表示二维平面上一些点的整数坐标,其中 points[i] = [xi, yi] 。
两点之间的距离定义为它们的曼哈顿距离。
请你恰好移除一个点,返回移除后任意两点之间的 最大 距离可能的 最小 值。
示例 1:
输入:points = [[3,10],[5,15],[10,2],[4,4]]
输出:12
解释:移除每个点后的最大距离如下所示:

  • 移除第 0 个点后,最大距离在点 (5, 15) 和 (10, 2) 之间,为 |5 - 10| + |15 - 2| = 18 。
  • 移除第 1 个点后,最大距离在点 (3, 10) 和 (10, 2) 之间,为 |3 - 10| + |10 - 2| = 15 。
  • 移除第 2 个点后,最大距离在点 (5, 15) 和 (4, 4) 之间,为 |5 - 4| + |15 - 4| = 12 。
  • 移除第 3 个点后,最大距离在点 (5, 15) 和 (10, 2) 之间的,为 |5 - 10| + |15 - 2| = 18 。
    在恰好移除一个点后,任意两点之间的最大距离可能的最小值是 12 。
    示例 2:
    输入:points = [[1,1],[1,1],[1,1]]
    输出:0
    解释:移除任一点后,任意两点之间的最大距离都是 0 。

提示:
3 <= points.length <= 105
points[i].length == 2
1 <= points[i][0], points[i][1] <= 108

数学

假定p1到p2的距离最大,则如果不删除p1或p2,最大距离一定不会变小。
我们只需要找到任意一对p1、p2,分别尝试删除p1和p2的最大距离。问题就转化成求:最大曼哈顿距离。
最大曼哈顿距离,应该有公式和模板。但我没有。这两天在研究线段树,就用线段树。结果11:59才完成编码。赛下,调试了一个小时才搞定。

线段树

将points 按x排序,i表示第一个点,j表示第二个点。则xi <= xj恒成立。只需要考虑yi和yj的大小。
{ x j − x i + y j − y i = ( x j + y j ) − ( x i + y i ) y i < = y j x j − x i + y i − y j = ( x j − y j ) − ( x i − y i ) y i > = y j \begin{cases} xj-xi+yj-yi = (xj+yj)-(xi+yi) && yi <= yj \\ xj-xi+yi-yj = (xj-yj)-(xi-yi) && yi >= yj \\ \end{cases} {xjxi+yjyi=(xj+yj)(xi+yi)xjxi+yiyj=(xjyj)(xiyi)yi<=yjyi>=yj
我们只需要计算 (xi+yi)和(xi-yi) 的最小值。用两棵最小树,分别记录最小值,单点更新,区间查找。难点:先要离散化,否则空间复杂度会超。

键值皆有序映射

情况一: yi <= yj
(xi+yi)和yj都越小越好,故键yj 升序,值(xi+yi)降序,如果冲突,淘汰键大的。
情况二:yi >= yj
(xi- yi) 越小越好,yj越大越好。故键yj升序,值(xi- yi)升序。发生冲突,淘汰键小的。

我看题解才知道的

切比雪夫距离(Chebyshev Distance) 在二维空间中,切比雪夫距离是通过计算两个点在各个坐标轴上的差值的绝对值中的最大值来衡量它。
曼哈顿距离在坐标轴旋转 45 度后与切比雪夫距离等价。

代码

线段树实现

class CDiscretize //离散化
{
public:CDiscretize(vector<int> nums){sort(nums.begin(), nums.end());nums.erase(std::unique(nums.begin(), nums.end()), nums.end());m_nums = nums;for (int i = 0; i < nums.size(); i++){m_mValueToIndex[nums[i]] = i;}}int operator[](const int value)const{auto it = m_mValueToIndex.find(value);if (m_mValueToIndex.end() == it){return -1;}return it->second;}int size()const{return m_mValueToIndex.size();}vector<int> m_nums;
protected:	unordered_map<int, int> m_mValueToIndex;
};template<class TSave, class TRecord>
class CSingUpdateLineTree
{
public:CSingUpdateLineTree(int iEleSize, TSave tDefautl) :m_iEleSize(iEleSize), m_vSave(iEleSize * 4, tDefautl) {}void Update(int index, TRecord update) {Update(1, 1, m_iEleSize, index + 1, update);}void Query(int leftIndex, int leftRight) {Query(1, 1, m_iEleSize, leftIndex + 1, leftRight + 1);}void Init() {Init(1, 1, m_iEleSize);}const int m_iEleSize;
protected:void Init(int iNodeNO, int iSaveLeft, int iSaveRight){if (iSaveLeft == iSaveRight) {OnInit(m_vSave[iNodeNO], iSaveLeft);return;}const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;Init(iNodeNO * 2, iSaveLeft, mid);Init(iNodeNO * 2 + 1, mid + 1, iSaveRight);OnUpdateParent(m_vSave[iNodeNO], m_vSave[iNodeNO * 2], m_vSave[iNodeNO * 2 + 1], iSaveLeft, iSaveRight);}void Query(int iNodeNO, int iSaveLeft, int iSaveRight, int iQueryLeft, int iQueryRight) {if ((iSaveLeft >= iQueryLeft) && (iSaveRight <= iQueryRight)) {OnQuery(m_vSave[iNodeNO]);return;}if (iSaveLeft == iSaveRight) {//没有子节点return;}const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;if (mid >= iQueryLeft) {Query(iNodeNO * 2, iSaveLeft, mid, iQueryLeft, iQueryRight);}if (mid + 1 <= iQueryRight) {Query(iNodeNO * 2 + 1, mid + 1, iSaveRight, iQueryLeft, iQueryRight);}}void Update(int iNodeNO, int iSaveLeft, int iSaveRight, int iUpdateNO, TRecord update) {if (iSaveLeft == iSaveRight){OnUpdate(m_vSave[iNodeNO], iSaveLeft, update);return;}const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;if (iUpdateNO <= mid) {Update(iNodeNO * 2, iSaveLeft, mid, iUpdateNO, update);}else {Update(iNodeNO * 2 + 1, mid + 1, iSaveRight, iUpdateNO, update);}OnUpdateParent(m_vSave[iNodeNO], m_vSave[iNodeNO * 2], m_vSave[iNodeNO * 2 + 1], iSaveLeft, iSaveRight);}virtual void OnInit(TSave& save, int iSave) = 0;virtual void OnQuery(TSave& save) = 0;virtual void OnUpdate(TSave& save,int iSaveLeft, const TRecord& update) = 0;virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r, int iSaveLeft, int iSaveRight) = 0;vector<TSave> m_vSave;
};template<class TSave=pair<int,int>, class TRecord =int>
class CMyLineTree : protected CSingUpdateLineTree<TSave, TRecord>
{
public:CMyLineTree(CDiscretize& dis,int iEleSize) : m_dis(dis),CSingUpdateLineTree<TSave, TRecord>(iEleSize,std::make_pair(1e9,-1)) {}void Update(int y, TRecord update) {CSingUpdateLineTree<TSave, TRecord>::Update(m_dis[y],update);}void QueryLessEqual(int y) {m_prMin = { 1e9,-1 };CSingUpdateLineTree<TSave, TRecord>::Query(0, m_dis[y]);}void QueryMoreEqual(int y) {m_prMin = { 1e9,-1 };CSingUpdateLineTree<TSave, TRecord>::Query(m_dis[y], m_dis.size()-1);}pair<int, int> m_prMin = { 1e9,-1 };
protected:virtual void OnInit(TSave& save, int iSave) override{}virtual void OnQuery(TSave& save) override{if (save < m_prMin) {m_prMin = save;}	}virtual void OnUpdate(TSave& save, int iSaveLeft,const TRecord& update) override{TSave tmp = { update,m_dis.m_nums[iSaveLeft - 1] };save = min(save,tmp);}virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r, int iSaveLeft, int iSaveRight) override{par = min(left, r);}	CDiscretize& m_dis;
}; 
class Solution {
public:int minimumDistance(vector<vector<int>>& points) {sort(points.begin(), points.end(), [](const auto& v1, const auto& v2) {return v1[0] < v2[0]; });auto [tmp, i1, i2] = Max(points);auto pts1 = points, pts2 = points;pts1.erase(pts1.begin() + i1);pts2.erase(pts2.begin() + i2);auto [m1, tmp1, tmp2] = Max(pts1);auto [m2, tmp3, tmp4] = Max(pts2);return min(m1, m2);}std::tuple<int, int, int> Max(const vector<vector<int>>& pts) {vector<int> ys;for (const auto& pt : pts) {ys.emplace_back(pt[1]);}CDiscretize dis(ys);CMyLineTree mXAndY(dis,dis.size()), mXSubY(dis, dis.size());const int n = pts.size();int iRet = -1e9,i2;std::pair<int, int> xy;for (int i = 1; i < n; i++) {mXAndY.Update(pts[i - 1][1], pts[i - 1][0] + pts[i - 1][1]);mXSubY.Update(pts[i - 1][1], pts[i - 1][0] - pts[i - 1][1]);mXAndY.QueryLessEqual(pts[i][1]);const int iDis1 = pts[i][0] + pts[i][1] - mXAndY.m_prMin.first;if (iDis1 > iRet) {iRet = iDis1;xy = { mXAndY.m_prMin.first- mXAndY.m_prMin.second, mXAndY.m_prMin.second };i2 = i;}mXSubY.QueryMoreEqual(pts[i][1]);const int iDis2 = pts[i][0] - pts[i][1] - mXSubY.m_prMin.first;if (iDis2 > iRet) {iRet = iDis2;xy = { mXSubY.m_prMin.first + mXSubY.m_prMin.second, mXSubY.m_prMin.second };i2 = i;}}int i1 = 0;for (; (xy.first != pts[i1][0]) || (xy.second != pts[i1][1]);i1++);return { iRet,i1,i2 };}
};

测试用例

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()
{vector<vector<int>> points;{points = { {9,8},{1,8},{3,1},{9,1},{7,7},{3,6} };auto res = Solution().minimumDistance(points);Assert(13, res);}{points = { {3,10},{5,15},{10,2},{4,4} };auto res = Solution().minimumDistance(points);Assert(12, res);}{points = { {3,2},{3,9},{7,10},{4,4},{8,10},{2,7} };auto res = Solution().minimumDistance(points);Assert(10, res);}{points = { {1,1},{1,1},{1,1},{1,1} };auto res = Solution().minimumDistance(points);Assert(0, res);}//CConsole::Out(res);
}

键值皆有需map

template<class _Kty, class _Ty, bool bValueAsc, bool bOutSmallKey>
class COrderValueMap
{
public:void Add(_Kty key, _Ty value){if (bOutSmallKey){if (bValueAsc){AddOutSmall(key, value, std::less_equal<_Ty>(), std::greater_equal<_Ty>());}else{AddOutSmall(key, value, std::greater_equal<_Ty>(), std::less_equal<_Ty>());}}else{if (bValueAsc){AddNotOutSmall(key, value, std::greater_equal<_Ty>(), std::less_equal<_Ty>());}else{AddNotOutSmall(key, value, std::less_equal<_Ty>(), std::greater_equal<_Ty>());}}};std::map<_Kty, _Ty> m_map;
protected:template<class _Pr1, class _Pr2>void AddOutSmall(_Kty key, _Ty value, _Pr1 pr1, _Pr2 pr2){auto it = m_map.lower_bound(key);if ((m_map.end() != it) && pr1(it->second, value)){return;//被旧值淘汰}auto ij = it;while (it != m_map.begin()){--it;if (pr2(it->second, value)){it = m_map.erase(it);}else{break;}}m_map[key] = value;}template<class _Pr1, class _Pr2>void AddNotOutSmall(_Kty key, _Ty value, _Pr1 pr1, _Pr2 pr2){auto it = m_map.upper_bound(key);if ((m_map.begin() != it) && pr1(std::prev(it)->second, value)){return;//被淘汰}auto ij = it;for (; (m_map.end() != ij) && pr2(ij->second, value); ++ij);m_map.erase(it, ij);m_map[key] = value;};};class Solution {
public:int minimumDistance(vector<vector<int>>& points) {sort(points.begin(), points.end(), [](const auto& v1, const auto& v2) {return v1[0] < v2[0]; });auto [tmp, i1, i2] = Max(points);auto pts1 = points, pts2 = points;pts1.erase(pts1.begin() + i1);pts2.erase(pts2.begin() + i2);auto [m1, tmp1, tmp2] = Max(pts1);auto [m2, tmp3, tmp4] = Max(pts2);return min(m1, m2);}std::tuple<int, int, int> Max(const vector<vector<int>>& pts) {COrderValueMap<int, int, false, false> mXAndY;COrderValueMap<int, int, true, true> mXSubY;const int n = pts.size();int iRet = -1e9,i2;for (int i = 1; i < n; i++) {mXAndY.Add(pts[i - 1][1], pts[i - 1][0] + pts[i - 1][1]);mXSubY.Add(pts[i - 1][1], pts[i - 1][0] - pts[i - 1][1]);auto it1 = mXAndY.m_map.upper_bound(pts[i][1]);if (mXAndY.m_map.begin() != it1 ) {--it1;const int iDis1 = pts[i][0] + pts[i][1] - it1->second;if (iDis1 > iRet) {iRet = iDis1;i2 = i;}}auto it2 = mXSubY.m_map.lower_bound(pts[i][1]);if (it2 != mXSubY.m_map.end()) {const int iDis2 = pts[i][0] - pts[i][1] - it2->second;if (iDis2 > iRet) {iRet = iDis2;i2 = i;}}}int i1 = -1,iMinDis=-1;for (int i = 0; i < n; i++) {const int curDis = abs(pts[i][0] - pts[i2][0]) + abs(pts[i][1] - pts[i2][1]);if (curDis > iMinDis) {iMinDis = curDis;i1 = i;}}return { iRet,i1,i2 };}
};

扩展阅读

视频课程

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

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

相关文章

PySpark的学习

一. 什么是PySpark 使用过的bin/pyspark 程序 , 要注意 , 这个只是一个 应用程序 , 提供一个 Python 解释器执行环境来运行 Spark 任务 现在说的 PySpark, 指的是 Python 的运行类库 , 是可以在 Python 代码中 :import pyspark PySpark 是 Spark 官方提供的一个 Python …

后端SpringBoot+Mybatis 查询订单数据库奇怪报错加一

排错过程&#xff1a; 看报错意思是SQL语句存在错误&#xff0c;然后使用图形化工具运行这个SQL语句 其实这里稍微细心想一下就能发现问题&#xff0c;但是当时没深入想&#xff0c;就觉得order表前加了数据库名字影响不大&#xff0c;所以感觉SQL语句是没问题的&#xff0c;然…

C语言 05 变量与常量

变量 变量就像在数学中学习的 x&#xff0c;y 一样&#xff0c;可以直接声明一个变量&#xff0c;并利用这些变量进行基本的运算&#xff0c;声明变量的格式为&#xff1a; 数据类型 变量名称 初始值;&#xff08;其中初始值可以不用在定义变量时设定&#xff09; 是赋值操作…

HarmonyOS实战开发-switch、chart组件的使用

介绍 本篇Codelab基于switch组件和chart组件&#xff0c;实现线形图、占比图、柱状图&#xff0c;并通过switch切换chart组件数据的动静态显示。要求实现以下功能&#xff1a; 实现静态数据可视化图表。打开开关&#xff0c;实现静态图切换为动态可视化图表。 相关概念 swit…

3. WiFi基本原理

1. WiFi简介 WiFi的全称是Wireless Fidelity。它是一种无线网络通信技术&#xff0c;由Wi-Fi联盟拥有&#xff0c;目的是改善基于IEEE 802.11标准的无线网络产品之间的互通性&#xff0c;允许电子设备在没有物理连接的情况下进行高速数据传输。此外&#xff0c;WiFi也被视为IE…

Holiday Notice

Holiday Notice 放假通知 要是每个公司都能放假放的多&#xff0c;把加班折算放假落实到位&#xff0c;还怕我们不努力干活&#xff0c;巴不得把全年都干完了&#xff0c;然后休息。

python爬取B站视频

参考&#xff1a;https://cloud.tencent.com/developer/article/1768680 参考的代码有点问题&#xff0c;请求头需要修改&#xff0c;上代码&#xff1a; import requests import re # 正则表达式 import pprint import json from moviepy.editor import AudioFileClip, Vid…

区间预测 | Matlab实现带有置信区间的GRNN广义回归神经网络时间序列未来趋势预测

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 Matlab实现带有置信区间的GRNN广义回归神经网络时间序列未来趋势预测 带有置信区间的GRNN(广义回归神经网络)时间序列未来趋势预测结合了广义回归神经网络(GRNN)的预测能力和置信区间的统计度量,以提供对未来…

云备份项目认识、环境搭建以及所使用的库的介绍

一、云备份认识 将本地计算机一个受监管的文件夹的文件上传到服务器中&#xff0c;有服务器组织&#xff0c;客户端可以通过网页将文件查看并且下载下来&#xff0c;下载过程支持断点续传功能&#xff0c;并且服务器会对上传的文件进行热点管理&#xff0c;长时间没人访问的文…

内网穿透时报错【Bad Request This combination of host and port requires TLS.】的原因

目录 前言&#xff1a;介绍一下内网穿透 1.内网直接https访问&#xff08;可以正常访问&#xff09; 程序配置的证书 2.内网穿透后,通过外网访问 3.原因 4.内网非https的Web应用&#xff0c;使用https后&#xff0c;也变成了https访问 5.题外话 感觉自己的web应用配置了…

使用 Seq2Seq 模型进行文本摘要

目录 引言 1 导入数据集 2 清洗数据集 3 确定允许的最大序列长度 4 选择合理的文本和摘要 5 对文本进行标记 6 删除空文本和摘要 7 构建模型 7.1 编码器 7.2 解码器 8 训练模型 9 测试模型 10 注意 11 整体代码 引言 文本摘要是指在捕捉其本质的同时缩短长文本的…

分布式之分布式事务详解

分布式事务与实战运用 什么是分布式事务&#xff1f; 业务场景&#xff1a;用户A转账100元给用户B&#xff0c;这个业务比较简单&#xff0c;具体的步骤&#xff1a; 1、用户A的账户先扣除100元 2、再把用户B的账户加100元 如果在同一个数据库中进行&#xff0c;事务可以保证…

209基于matlab的无人机路径规划

基于matlab的无人机路径规划&#xff0c;包括2D路径和3D路径&#xff0c;三种优化算法&#xff0c;分别是蝙蝠算法&#xff08;BA&#xff09;、蝙蝠算法融合差分进化算法(DEBA)、结合人工势场方法的改进混沌蝙蝠算法(CPFIBA)。输出距离迭代曲线和规划的路径。程序已调通&#…

云计算探索-如何在服务器上配置RAID(附模拟器)

一&#xff0c;引言 RAID&#xff08;Redundant Array of Independent Disks&#xff09;是一种将多个物理硬盘组合成一个逻辑单元的技术&#xff0c;旨在提升数据存取速度、增大存储容量以及提高数据可靠性。在服务器环境中配置RAID尤其重要&#xff0c;它不仅能够应对高并发访…

【跟小嘉学 Linux 系统架构与开发】二、Linux发型版介绍与基础常用命令介绍

系列文章目录 【跟小嘉学 Linux 系统架构与开发】一、学习环境的准备与Linux系统介绍 【跟小嘉学 Linux 系统架构与开发】二、Linux发型版介绍与基础常用命令介绍 文章目录 系列文章目录[TOC](文章目录) 前言一、 Linux 发行版(Linux distribution)介绍二、Centos 虚拟机初始化…

Yarn的安装和使用(2):使用及问题解决

Yarn是JavaScript的依赖管理工具&#xff0c;它与npm类似&#xff0c;但提供了一些额外的性能优化和一致性保证。 Yarn的使用&#xff1a; 初始化项目&#xff1a; yarn init 此命令会引导您创建一个新的package.json文件&#xff0c;用于记录项目的元信息和依赖。 添加依赖&…

【Linux在程序运行时打印调用栈信息(函数名,文件行号等)】

在程序运行时打印相关调用栈信息&#xff08;函数名&#xff0c;文件行号等&#xff09;,便于梳理调用逻辑等 //stack.c #include <stdio.h> #include <execinfo.h> #include <stdlib.h> #include <string.h> #include <stdbool.h>#define MAX_…

如何通过Elasticsearch实现搜索的关键词达到高亮的效果

高亮 首先介绍一下什么是搜索的关键词达到高亮的效果&#xff0c;如图所示 当在百度里面搜索elasticsearch的时候&#xff0c;可以看到出现的搜索结果里面elasticsearch这个关键词明显与其他的条文不一样&#xff0c;用红颜色凸显了“高亮效果”。当我们想要在自己的项目里面…

手机有线投屏到直播姬pc端教程

1 打开哔哩哔哩直播姬客户端并登录(按下图进行操作) 2 手机用usb数据线连接电脑(若跳出安装驱动的弹窗点击确定或允许),usb的连接方式为仅充电(手机差异要求为仅充电),不同品牌手机要求可能不一样,根据实际的来 3 在投屏过程中不要更改usb的连接方式(不然电脑会死机需要重启) …

MultiPath HTTP:北大与华为合作部署FLEETY

当前的终端基本都能支持蜂窝网络和wifi网络&#xff0c;然而&#xff0c;不同的网络通路都不可避免的会出现信号不好或者其他因素引起的通路性能(吞吐量、时延等)下降。为了能够提升终端业务体验&#xff0c;很多不同的MultiPath方案被提出&#xff0c;其中&#xff0c;包括应用…