无重叠区间及用最少的箭射爆气球

文章目录

  • 无重叠区间及用最少的箭射爆气球
    • **一:开胃菜**
    • **二、无重叠区间**
    • **三、用最少的箭射爆气球**

一:开胃菜

在开始所无重叠区间前先做一道简单的提来铺垫一下

给你很多形如 [start, end] 的闭区间, 请你设计⼀个算法,
算出这些区间中最多有⼏个互不相交的区间

int intervalSchedule(int[][] intvs) {}

举个例⼦, intvs = [[1,3], [2,4], [3,6]] , 这些区间最多有 2 个区间互不相交, 即 [[1,3], [3,6]] , 你的算法应该返回 2。 注意边界相同并不算相交。

这个问题有许多看起来不错的贪⼼思路, 却都不能得到正确答案。 ⽐如说:

也许我们可以每次选择可选区间中开始最早的那个? 但是可能存在某些区间开始很早, 但是很⻓, 使得我们错误地错过了⼀些短的区间

或者我们每次选择可选区间中最短的那个? 或者选择出现冲突最少的那个区间? 这些⽅案都能很容易举出反例, 不是正确的⽅案

正确的思路其实很简单, 可以分为以下三步:

  1. 从区间集合 intvs 中选择⼀个区间 x, 这个 x 是在当前所有区间中结束最早的(end 最⼩) 。

  2. 把所有与 x 区间相交的区间从区间集合 intvs 中删除。

  3. 重复步骤 1 和 2, 直到 intvs 为空为⽌。 之前选出的那些 x 就是最⼤不相交⼦集

把这个思路实现成算法的话, 可以按每个区间的 end 数值升序排序, 因为这样处理之后实现步骤 1 和步骤 2 都⽅便很多:

现在来实现算法, 对于步骤 1, 由于我们预先按照 end 排了序,所以选择x 是很容易的。 关键在于, 如何去除与 x 相交的区间, 选择下⼀轮循环的 x呢?

由于我们事先排了序不难发现所有与 x 相交的区间必然会与 x 的 end 相交; 如果⼀个区间不想与 x 的 end 相交, 它的 start 必须要⼤于(或等于) x 的 end

直接看代码:

public int intervalSchedule(int[][] intvs) {if (intvs.length == 0) return 0;// 按 end 升序排序Arrays.sort(intvs, new Comparator<int[]>() {public int compare(int[] a, int[] b) {return a[1] - b[1];}}// 记录不相交区间的个数,初始化时⾄少有⼀个区间不相交int count = 1;// 排序后, 第⼀个区间就是 xint x_end = intvs[0][1];for (int[] interval : intvs) {int start = interval[0];//代表这个区间和选择的区间不相交,更新相关变量if (start >= x_end){// 找到下⼀个选择的区间了count++;x_end = interval[1];}} return count;
}

二、无重叠区间

给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。

注意:

可以认为区间的终点总是大于它的起点。 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。

示例 1:

输入: [ [1,2], [2,3], [3,4], [1,3] ]输出: 1解释: 移除 [1,3] 后,剩下的区间没有重叠。

示例 2:

输入: [ [1,2], [1,2], [1,2] ]输出: 2解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。

示例 3:

输入: [ [1,2], [2,3] ]输出: 0解释: 你不需要移除任何区间,因为它们已经是无重叠的了。

我们已经会求最多有⼏个区间不会重叠了, 那么剩下的不就是⾄少需要去除的区间吗?

int eraseOverlapIntervals(int[][] intervals) {int n = intervals.length;return n - intervalSchedule(intervals);
}

完整C++代码

class Solution {public:int eraseOverlapIntervals(vector<vector<int>>& intervals) {if (intervals.empty()) return 0;//先对vector进行排序sort(intervals.begin(), intervals.end());//记录左边界,[start,end]相当于end位置的元素int left = intervals[0][1];//记录要移除的个数int res = 0;//循环测试for (int i = 1; i < intervals.size(); ++i) {//如果intervals[i][0] < left(相当于上一个区间的 end 大于循环测试的start)代表两个区间重复,更新左边界及计数if (intervals[i][0] < left) {++res;//left在区间重复的情况下,左边界相当于取上一个区间的end 和 循环测试的某个区间的end的最小值left = min(left, intervals[i][1]);} else {//两个区间没有相交,直接判断下一个区间left = intervals[i][1];}}return res;}
};

三、用最少的箭射爆气球

在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以y坐标并不重要,因此只要知道开始和结束的x坐标就足够了。开始坐标总是小于结束坐标。平面内最多存在104个气球。

一支弓箭可以沿着x轴从不同点完全垂直地射出。在坐标x处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。

Example:

输入:
[[10,16], [2,8], [1,6], [7,12]]输出:
2解释:
对于该样例,我们可以在x = 6(射爆[2,8],[1,6]两个气球)和 x = 11
(射爆另外两个气球)。

其实稍微思考⼀下, 这个问题和区间调度算法⼀模⼀样,只不过是气球变成了区间而已! 如果最多有 n 个不重叠的区间, 那么就⾄少需要 n 个箭头穿透所有区间:

只是有⼀点不⼀样, 在 intervalSchedule 算法中, 如果两个区间的边界触碰, 不算重叠; ⽽按照这道题⽬的描述(开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被引爆), 箭头如果碰到⽓球的边界⽓球也会爆炸, 所以说相当于区间的边界触碰也算重叠:

所以只要将之前的算法稍作修改, 就是这道题⽬的答案:

int findMinArrowShots(int[][] intvs) {//for (int[] interval : intvs) {int start = interval[0];// 把 >= 改成 > 就⾏了if (start > x_end) {count++;x_end = interval[1];}} return count;
}

完整C++代码

class Solution {public:int findMinArrowShots(vector<vector<int>>& points) {if(points.empty()){return 0;}//排序sort(points.begin(),points.end());//定义第一个区间的结束位置为end,后序区间都会和end进行比较int end = points[0][1];//用来计数int count = 1;//循环遍历所有区间for(int i = 1;i < points.size();i++){//定义每个区间的开始位置为startint start = points[i][0];//如果start > end 说明两个区间没有重叠,更新相关变量if(start > end){++count;end = points[i][1];}else{//取当前end和重叠区间的end的较小值end = min(end,points[i][1]);}}return count;}
};

无重叠区间及用最少的箭射爆气球相关推荐

  1. 用少量箭射爆气球,leetcode习题

    用少量气球射爆气球 在二维空间中有许多球形的气球.对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标.由于它是水平的,所以纵坐标并不重要,因此只要知道开始和结束的横坐标就足够了.开始坐标总 ...

  2. 力扣记录:贪心算法3较难(1)区间问题——55 跳跃游戏,45 跳跃游戏II,452 用最少数量的箭引爆气球,435 无重叠区间,763 划分字母区间,56 合并区间

    本次题目 55 跳跃游戏 45 跳跃游戏II 452 用最少数量的箭引爆气球 435 无重叠区间 763 划分字母区间 56 合并区间 55 跳跃游戏 局部最优:不管每次跳多少步,取最大跳跃步数,若覆 ...

  3. 贪心算法无重叠区间c语言,贪心算法之区间问题.md

    --- title: 贪心算法之区间问题 tags: - Leetcode categories: - Leetcode author: 四叶草 top: false abbrlink: 26230 ...

  4. day36-435. 无重叠区间

    435. 无重叠区间 思路: 遇到二维数组的区间问题,先排序.画图,按照start递增排序,如果start相等则按照end递增. 为什么按照start递增排序?保证start有序,每个item的sta ...

  5. 通俗易懂:贪心算法(二):区间问题 (力扣435无重叠区间)

    看完本文,可以顺便解决leetcode以下题目: 435.无重叠区间(中等) 一.通俗易懂的 贪心算法 |思想 (重复一次~~~) 贪心算法就是采用贪心的策略,保证每一次的操作都是局部最优的,从而使得 ...

  6. Leetcode-435:无重叠区间

    题目链接 Leetcode-435:无重叠区间 题目描述 给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠. 注意: 可以认为区间的终点总是大于它的起点. 区间 [1,2] 和 [2 ...

  7. 435. 无重叠区间

    435. 无重叠区间 给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠. 注意: 可以认为区间的终点总是大于它的起点. 区间 [1,2] 和 [2,3] 的边界相互"接触& ...

  8. LeetCode435—无重叠区间(java版)

    题目描述: 标签:贪心算法    给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠. 注意: 可以认为区间的终点总是大于它的起点. 区间 [1,2] 和 [2,3] 的边界相互&qu ...

  9. Leetcode 435.无重叠区间 (每日一题 20210708 同类型题)

    给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠.注意:可以认为区间的终点总是大于它的起点. 区间 [1,2] 和 [2,3] 的边界相互"接触",但没有相互重叠 ...

最新文章

  1. AI科研绘图3:排版
  2. MongoDB源码概述——使用日志提升单机数据可靠性
  3. 小调查:足足两周了,下周你上班否?
  4. Windows Server 2008 如何在IIS中添加MIME类型
  5. 自定义例外:当没有查询到员工信息时,抛出例外
  6. 内网渗透-域内有网和无网
  7. Struts2学习笔记04 之 拦截器
  8. SQL Server 性能优化之——系统化方法提高性能
  9. ul 原点显示_html ul li在div里圆点靠左对齐
  10. 昌吉学院2017年计算机招生,昌吉学院
  11. 内容分发网络(CDN)关键技术、架构与应用(一)
  12. 第十届蓝桥杯 省赛研究生组 真题解析(Python)
  13. 电力相关的中文期刊查找
  14. React Antd4 CRA / Next.js / Vite 按需加载组件的 CSS / Less
  15. 小程序怎么弄?小程序开发多少钱?
  16. 安装多可预览控件后,不能正常预览和修改该怎么办?
  17. nvme分区选mbr还是guid_怎么分辨硬盘是GUID格式还是MBR格式以及怎样更改
  18. 唐骏:身价10亿不买房 每月12万住宾馆
  19. HBuilder常用快捷键
  20. uniCloud云开发入门:了解云函数、云数据库、云存储的基本概念

热门文章

  1. 笔试编程常用函数(Java)
  2. 四种π型RC滤波电路
  3. linux中shell变量$#,$@,$0,$1,$2的含义解释:
  4. SVN在另类环境中实现自动提交的方法
  5. Web开发中的用户角色权限设计总结
  6. 【学习笔记11】动态方法调用和使用通配符定义action
  7. [学习笔记]Hadoop 配置调试错误收集
  8. 通过shell脚本实现批量更改密码
  9. 中石油训练赛 - Fermat‘s Optimization Problem(Java高精度运算+二分)
  10. 洛谷 - P1361 小M的作物(最大流最小割)