【刷题之路Ⅱ】LeetCode 475. 供暖器

news2024/11/22 22:21:22

【刷题之路Ⅱ】LeetCode 475. 供暖器

  • 一、题目描述
  • 二、解题
    • 1、方法1——排序后二分法
      • 1.1、思路分析
      • 1.2、代码实现
    • 2、方法2——排序后双指针
      • 2.1、思路分析
      • 2.2、代码实现

一、题目描述

原题连接: 475. 供暖器
题目描述:
冬季已经来临。 你的任务是设计一个有固定加热半径的供暖器向所有房屋供暖。
在加热器的加热半径范围内的每个房屋都可以获得供暖。
现在,给出位于一条水平线上的房屋 houses 和供暖器 heaters 的位置,请你找出并返回可以覆盖所有房屋的最小加热半径。

说明:所有供暖器都遵循你的半径标准,加热的半径也一样。

示例 1:

输入: houses = [1,2,3], heaters = [2]
输出: 1
解释: 仅在位置2上有一个供暖器。如果我们将加热半径设为1,那么所有房屋就都能得到供暖。

示例 2:

输入: houses = [1,2,3,4], heaters = [1,4]
输出: 1
解释: 在位置1, 4上有两个供暖器。我们需要将加热半径设为1,这样所有房屋就都能得到供暖。

示例 3:

输入: houses = [1,5], heaters = [2]
输出: 3

提示:
1 <= houses.length, heaters.length <= 3 * 104
1 <= houses[i], heaters[i] <= 109

二、解题

1、方法1——排序后二分法

1.1、思路分析

可能有的朋友在看完题目之后还搞不清楚题目要描述的场景,那我这里就先化身“灵魂画手”给大家画出场景图来:
在这里插入图片描述
如上图,题目中描述的场景大致如上图所示,假设地平线就是一根数轴,那么在这些数轴的坐标上分布着一些房子和供暖器,这些房子可能包围着一些供暖器,也有可能同一个坐标上同时有房子和供暖器,而这些供暖器也有可能不在房子的范围内。
我们要做的就是要找到一个最小的半径,以使得所有的供暖器在同时工作并且供暖半径相同的情况下能够供暖到所有的房子。
其实还有一点需要注意的是,如果一个坐标上同时存在房子和供暖器,那么久这个坐标上而言,这个供暖器的供暖半径为0就能够供暖到这个房子
那我们应该怎样解决这个问题呢?
其实我们可以现针对每一个房子,找到离它最近的一个供暖器,那么这个供暖器能供暖到它的最小供暖半径就是他们的距离之差:
在这里插入图片描述

然后我们再求出每个房子到离它最近的供暖器的距离的最大值,这个最大值就是我们所要求的对于所有房子的最小供暖半径。
有些朋友可能会觉得有点儿绕啊,这一会儿最小值一会儿最大值的,这感觉怎么有点儿像我们在高中时候学的数学中的求函数的极值问题呢?
不过这个并没有函数极值那么绕人啦,其实就是需要满足所有房子都能被供暖到,所以我们才需要求最大值。

而在实际的操作中,为了找到距离某个房子的距离最小的供暖器,我们其实要找到两个供暖器,即左右两端最接近这个房子的供暖器,然后求出这两个距离的最小值即可:
在这里插入图片描述
而如果对于某个房子的左端或右端没有供暖器的情况,很简单,我们就把这一段的距离设置长无穷大即可。

为了能更好的找到距离某个房子最近的供暖器,我们可以先将heaters数组进行排序,然后使用二分法找边界的方法找到第一个位置大于当前房子的位置的供暖器即可。
假设,heaters[j]为第一个位置大于houses[i],的供暖器,那么heaters[j]就是右端最接近houses[i]的供暖器,而heaters[j - 1]即是左端最接近houses[i]的供暖器。

1.2、代码实现

有了以上思路,那我们写起代码来也就水到渠成了:

int max(int x, int y) {
    return x > y ? x : y;
}
int min(int x, int y) {
    return x < y ? x : y;
}

int cmp_int(const void *p1, const void *p2) {
    return *((int*)p1) - *((int*)p2);
}

// 二分法找边界法
int binarySearch(int *nums, int left, int right, int target) {
    int numsSize = right + 1;
    int mid = 0;
    while (left < right) {
        if (nums[left] > target) {
            return left;
        }
        mid = left + (right - left) / 2;
        if (nums[mid] <= target) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }
    return nums[left] > target ? left : numsSize; // 如果没有找到,就返回数组的长度,表示找不到
}



int findRadius(int* houses, int housesSize, int* heaters, int heatersSize) {
    // 先将数组heaters进行排序
    qsort(heaters, heatersSize, sizeof(int), cmp_int);
    int i = 0;
    int minR = 0;
    for (i = 0; i < housesSize; i++) {
        int rightHeaterIndex = binarySearch(heaters, 0, heatersSize - 1,houses[i]);
        int leftHeaterIndex = rightHeaterIndex - 1;
        int leftDistance = leftHeaterIndex < 0 ? INT_MAX : houses[i] - heaters[leftHeaterIndex];
        int rightDistance = rightHeaterIndex >= heatersSize ? INT_MAX : heaters[rightHeaterIndex] - houses[i];
        int curR = min(leftDistance, rightDistance);
        minR = max(curR, minR);
    }
    return minR;
}

时间复杂度:O((n+m)logn),其中m是数组houses的长度,n是数组heaters的长度,对数组heaters排序的复杂度为O(nlogn)。而对于houses中的每个元素,我们都得使用二分法在heaters数组中查找,复杂度为O(mlogn)。故合并的复杂度为O((n+m)logn)。
空间复杂度:O(logn),n为数组heaters的长度,空间复杂度主要取决于排序所需要的空间。

2、方法2——排序后双指针

2.1、思路分析

通过方法1的解法我们应该能够得到启发,其实对于每个房子我们只需要找到距离它最近的房子即可。
那么我们是否能再次优化以下呢?
当然是可以的,其实我们完全可以利用上一个房子查找的结构来辅助查找到下一个房子的离它最近的供暖器,例如:
在这里插入图片描述
如上图所示,离坐标为3的房子最近的是坐标为0的供暖器,那么对于下一个坐标为5的房子,离它最近的房子就只有可能是坐标为0的供暖器或者在坐标为0的供暖器右端的供暖器,这里很明显就是在在右端的坐标为7的供暖器。
所以这就很好地利用了上一个坐标为3的房子的查找结果了。
沿着这个思路,我们也能找到距离下标为5和9的房子最近的供暖器是同一个:
在这里插入图片描述
而这个操作正好可以使用双指针来完成,如下图:
在这里插入图片描述
我们使用两个指针j和i分别来遍历供暖器和房子,当j的下一个供暖器距离i的距离更近的时候,就让j往前走,直到走到j的下一个供暖器距离i更远:
在这里插入图片描述
然后我们就记录这个距离,这就是距离i最近的供暖器的距离。
然后我们就让i完后走,查找下一个房子的。

2.2、代码实现

有了以上思路,那我们写起代码来也就水到渠成了:

int max(int x, int y) {
    return x > y ? x : y;
}
int min(int x, int y) {
    return x < y ? x : y;
}

int cmp_int(const void *p1, const void *p2) {
    return *((int*)p1) - *((int*)p2);
}

int findRadius(int* houses, int housesSize, int* heaters, int heatersSize) {
    // 先将两个数组进行排序
    qsort(heaters, heatersSize, sizeof(int), cmp_int);
    qsort(houses, housesSize, sizeof(int), cmp_int);

    int minR = 0;
    int curR = 0;
    int i = 0;
    int j = 0;
    for (i = 0, j = 0; i < housesSize; i++) {
        
        curR = abs(houses[i] - heaters[j]);
        while (j < heatersSize - 1 && abs(houses[i] - heaters[j + 1]) <= abs(houses[i] - heaters[j])) {
            j++;
            curR = min(curR, abs(houses[i] - heaters[j]));
        }
        minR = max(curR, minR);
    }
    return minR;
}

时间复杂度:O(nlogn + mlogm),n和m分别是数组heaters和数组houses的长度。
空间复杂度:(logn + logm),空间复杂度主要取决于排序所需要的口空间。

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

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

相关文章

怎样能把两张照片拼成一张图片,5种工具分享

怎样能把两张照片拼成一张图片&#xff1f;图片拼合的应用场景是很多的。比如将几张相册中的照片拼成一张合影、将多个地图截图拼合在一起形成一个更大的区域地图、将多个漫画图像合并成一本漫画册等。这项技术可以方便地将多张图片整合为一张&#xff0c;节省时间和精力。 因此…

ThinkPHP6布局的方式之模板布局,全局配置方式,模板标签方式,动态方法布局

ThinkPHP6布局的方式之模板布局 ThinkPHP的模板引擎内置了布局模板功能支持&#xff0c;可以方便的实现模板布局以及布局嵌套功能。 有三种布局模板的支持方式&#xff1a;全局配置方式&#xff0c;模板标签方式&#xff0c;动态方法布局。 第一种方式&#xff1a;全局配置方…

有价值项目分享,缺项目可直接搜索(持续更新中)

​近来统计一下最近发的一些资源&#xff0c;包括CSDNB站微信公众号三个平台&#xff0c;仅包括Java资源&#xff08;SSMSpringBootuniapp&#xff09;、部分硬件、安卓资源&#xff0c;一共30758492588275个&#xff0c;可覆盖95%的毕业题目&#xff0c;大家可在相关归档内获取…

2023 年破解 PDF 密码的 5 种最佳方法

世界越来越依赖数字文档和信息存储。最流行和广泛使用的数字文档文件格式之一是便携式文档格式 (PDF)。PDF 文件用途广泛、可靠&#xff0c;并提供高级别的安全性以保护敏感信息免遭未经授权的访问。保护 PDF 的一种常用方法是通过密码保护。在这篇博文中&#xff0c;我们将讨论…

从SRM到采购供应链,云时通SRM助力东明实现采购数字化再升级!

随着制造业不断向高端跃升&#xff0c;十年来&#xff0c;中国制造企业早已具备全球领先水平。而引领制造业向数字化、网络化、智能化转型升级&#xff0c;是中国智造进一步跨越的关键。 1995年&#xff0c;浙江东明不锈钢制品股份有限公司(以下简称“东明”)成立&#xff0c;作…

超细!从零安装压测工具 jmeter(附JDK下载安装教程,20230516的JDK8最新版)

两步走&#xff0c;安装 JDK 和 jmeter&#xff0c;如果安装了JDK的同志可以直接看第二步。 针对的操作系统&#xff1a;Windows。 下载JDK 官网指路&#xff08;处于稳定性考虑&#xff0c;安装的JDK8&#xff09;&#xff1a; Java Downloads | Oraclehttps://www.oracle.c…

Java配置方式使用Spring MVC

文章目录 基于Java配置方式使用Spring MVC一、创建Maven项目二、添加相关依赖三、创建日志属性文件四、创建首页文件五、创建Spring MVC配置类六、创建Web应用初始化配置类七、创建演示控制器八、配置Tomcat服务器九、启动服务器&#xff0c;查看效果 基于Java配置方式使用Spri…

「计算机网络」HTTP1.0、HTTP1.1和HTTP2.0的演变

「计算机网络」HTTP1.0、HTTP1.1和HTTP2.0的演变 参考&鸣谢 HTTP1.0、HTTP1.1、HTTP2.0的关系和区别 doubleYong 计算机网络_HTTP1.0、HTTP1.1和HTTP2.0的区别 一只前端小马甲 文章目录 「计算机网络」HTTP1.0、HTTP1.1和HTTP2.0的演变一、先说结论二、HTTP网络请求过程三…

【01】一步一步命令行输出VC hello world

一步一步命令行输出VC hello world 安装VS2022编写hello world程序配置cl.exe编译helloworld.cpp总结 安装VS2022 VS2022的安装程序下载地址:https://visualstudio.microsoft.com/zh-hans/downloads/ 。下载完成之后点击程序会进入到选择安装VS2022组件的安装程序&#xff0c;…

小红的好数组陡峭值之和

题目如下 这个题我一开始是先生成满足0&#xff0c;1&#xff0c;2的全排列&#xff0c;但是n很大时很快就超出内存限制了&#xff0c;后来想到用动态规划的方法做&#xff0c;这里先分析一下。 n2时&#xff0c;有01&#xff0c;02&#xff0c;10&#xff0c;12&#xff0c;2…

自动化设备应用之样本手册

Lookbook&#xff0c;新品展示图&#xff0c;是时尚品牌的必备品。Lookbook既展示了新系列&#xff0c;也突出了品牌的基本调性。创建样本手册是释放创造力并从其他时装设计师中脱颖而出的机会。有吸引力的封面、精心策划的图像、精巧的布局、颜色标识和传达风格都是品牌内容传…

建构筑物安全监测

监测要求 1&#xff09;观测点应设置在观测段结构构件的控制断面上&#xff1b; 2&#xff09;平面应力状态的结构应力观测宜设置三向应变观测点,主应力方向明晩的部位可设置单向或两向应变观测点&#xff1b; 3&#xff09;建筑物的重要部位应增设观测点&#xff1b; 4&am…

ControlNet让SD变得可控

ControlNet是一个用于深度神经网络的控制技术&#xff0c;它可以通过操作神经网络块的输入条件来控制神经网络的行为。在这里&#xff0c;“网络块”是指常用的神经层集合&#xff0c;例如“resnet”块、“conv-bn-relu”块、多头注意力块等。通过克隆神经网络块的参数并应用零…

软考A计划-真题-分类精讲汇总-第十七章(数据结构与算法)

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

智慧档案馆建设之八防十防常用的设备

档案八防十防常用的十款设备 序号 名称 1 温湿度传感器 2 空气质量云测仪 3 恒湿净化一体机 4 健康防护一体机 5 综合智能触摸一体化区域控制器 6 空调红外学习控制模块 7 漏水检测控制器及感应线 8 数字烟雾传感器 9 红外防盗传感器 10 系统软件平台 附…

redis高级篇(1)

分布式缓存 单节点redis的问题: 1)数据丢失的问题&#xff0c;redis是基于内存来进行存储的&#xff0c;当服务器重启的时候可能会丢失数据 2)无法满足高并发场景 3)如果redis宕机&#xff0c;那么这个服务不可用&#xff0c;所以就需要有一种自动的故障恢复手段&#xff0c;必…

从裸机启动开始运行一个C++程序(一)

前言 对于一个C程序员来说&#xff0c;可能更多是是每天都在跟各种上层语义、设计模式、软件方法等等在打交道。但对于「一个C程序是如何运行在机器上的」这件事可能会比较陌生。有时&#xff0c;遇到一些问题&#xff0c;在宏观角度看起来可能比较难以解释&#xff0c;但其实…

activiti6是使用,或签,会签

会签&#xff1a;指同一个审批节点设置多个人&#xff0c;如ABC三人&#xff0c;三人会同时收到审批&#xff0c;需全部同意之后&#xff0c;审批才可到下一审批节点&#xff1b; 或签&#xff1a;也有叫“竞签”、“串签”&#xff1a;指同一个审批节点设置多个人&#xff0c;…

电脑上删除掉的文件怎么恢复?一文告诉你详细恢复方法!

对于不太会整理电脑的用户来讲&#xff0c;电脑上的文件一旦保存多了&#xff0c;不但会使得电脑看上去很杂乱&#xff0c;还会在我们需要寻找某一个文件的时候&#xff0c;半天都找不到。 所以&#xff0c;对于一些可能不会再需要的文件&#xff0c;我们会选择直接删除&#x…

Dart 3.0 语法新特性 | 类型修饰符 Class modifiers

theme: cyanosis 在 dart 3.0.0 之后&#xff0c;对类型的修饰符进行了拓展&#xff0c;现在类型的修饰符有&#xff1a; | 名称 | 作用 | | --- | --- | | mixin | 混入类修饰符 | | sealed | 密封可枚举的子类型 | | abstract | 抽象类修饰符 | | final | 一定程度上关闭派生…