文章目录
- 前言
- 一、根据身高重建队列(力扣406)
- 二、用最少数量的箭引爆气球(力扣452)
- 三、无重叠区间(力扣435)
前言
1、根据身高重建队列
2、用最少数量的箭引爆气球
3、无重叠区间
一、根据身高重建队列(力扣406)
假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。
请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。
思路:
上了第一节体育课,老师给大家排好了体操的队伍,可是大家脑子都很笨,记不清自己在哪,老师说,你就看前面有几个比自己高的就行!就像这样:
[[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
该上第二节课的时候,大家记住了前面有几个比自己高的,却还是忘记了怎么排,老师见状让学生从高到低排好队,身高一样的,比自己高的越多,越往后面站,像这样:
[[7,0],[7,1],[6,1],[5,0],[5,2],[4,4]]
每次让最高的学生出来找自己的位置,第一个高个子[7,0]自然站到了第一个位置:
[[7,0]]
而第二个高个子[7,1]知道有一个人大于等于自己的身高,站在了第一个人身后:
[[7,0],[7,1]]
第三个人[6,1]想了想,有一个人比自己高,那自己肯定站在第二位,于是就插队,现在也站到了第一个人身后:
[[7,0],[6,1],[7,1]]
第四个人[5,0]想了想,没人比自己高,那自己肯定站在第一位,于是就插队,站到了队头:
[[5,0],[7,0],[6,1],[7,1]]
第五个人[5,2]想了想,有两个人比自己高,于是就插队,站到了第二个人后面,也就是第三个位置:
[[5,0],[7,0],[5,2],[6,1],[7,1]]
第六个人[4,4]看了看眼前的队伍,比自己高的人都在里面,他安心的数着前面有四个人比自己高,心安理得的站到了第四个人身后:
[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
其实这道题的大概思路就是这样,只有先让身高高的先进入队伍,后面身高低的才能根据前面高的来找自己的位置,
遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度。如果两个维度一起考虑一定会顾此失彼。
按照身高h来排序,身高一定是从大到小排(身高相同的话则k小的站前面),让高个子在前面。此时我们可以确定一个维度了,就是身高,前面的节点一定都比本节点高!
class Solution {
public int[][] reconstructQueue(int[][] people) {
//身高从大到小排(身高相同k小的站前面)
Arrays.sort(people,(a,b)->{
if(a[0]==b[0]) return a[1]-b[1];
return b[0]-a[0];
});
LinkedList<int[]> que = new LinkedList<>();
for(int[] p:people){
que.add(p[1],p);
}
return que.toArray(new int[people.length][]);
}
}
二、用最少数量的箭引爆气球(力扣452)
有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。
一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。
给你一个数组 points ,返回引爆所有气球所必须射出的 最小 弓箭数 。
思路:
以题目示例: [[10,16],[2,8],[1,6],[7,12]]为例,如图:(方便起见,已经排序)
class Solution {
public int findMinArrowShots(int[][] points) {
Arrays.sort(points,(a,b)->Integer.compare(a[0],b[0]));
int res = 1;
for(int i=1;i<points.length;i++){
if(points[i][0]>points[i-1][1]){ //不挨着
res++;
}else{
points[i][1]=Math.min(points[i][1],points[i-1][1]);//比较重要,更新重叠气球最小右边界
}
}
return res;
}
}
三、无重叠区间(力扣435)
给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。
思路:
利用上一题思路来求解
最后用区间总数减去非交叉区间的个数就是需要移除的区间个数了。
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals,(a,b)->Integer.compare(a[0],b[0]));
int res = 1;
for(int i=1;i<intervals.length;i++){
if(intervals[i][0]>=intervals[i-1][1]){ //不挨着
res++;
}else{
intervals[i][1] = Math.min(intervals[i][1],intervals[i-1][1]);
}
}
return intervals.length-res;
}
}