452. 用最少数量的箭引爆气球
每次射箭尽量往区间的右边射,这样可以用尽可能少的箭引爆更多的气球。先按右边界排序,然后维护变量backLimit,假设某时刻有m个气球可以用一箭全射,那么只需要满足:第一个气球的右边界 >= 其余气球的左边界,然后箭从第一个气球的右边界位置处发射。第m+1个气球发现不满足了,那么更新backLimit,ans++,表示又需要一箭。
按左边界排序应该也可以,只不过遍历的顺序得倒过来。
/**
* @param {number[][]} points
* @return {number}
*/
var findMinArrowShots = function (points) {
points.sort((a, b) => a[1] - b[1]);
const len = points.length;
let ans = 0;
let i = 0;
while (i < len) {
ans++; // 箭数
const backLimit = points[i][1];
// 箭从backLimit位置处发射,看后面哪些气球可以被这一箭射爆
let j = i + 1;
while (j < len && points[j][0] <= backLimit) {
j++;
}
// 不能被这一箭射爆的第一个气球
i = j;
}
return ans;
};
435. 无重叠区间
方法一和上一题类似,但是求的是需要去除的区间的最小个数,何为重叠区间,就是当规定了本轮的backLimit后,左顶点 < backLimit的那些区间(顶点相连不是重叠)。
方法二则是在区间重叠时无动于衷,遇到了不重叠的区间,就更新此时的backLimit,统计了不重叠区间的个数,再用总区间数相减。
// 方法一
var eraseOverlapIntervals = function(intervals) {
intervals.sort((a, b) => a[1] - b[1])
let ans = 0 // 重叠区间的个数
let backLimit
let i = 0
const len = intervals.length
while (i < len) {
backLimit = intervals[i][1]
let j = i + 1
while (j < len && intervals[j][0] < backLimit) {
ans++, j++
}
i = j
}
return ans
};
// 方法二
var eraseOverlapIntervals = function(intervals) {
if (intervals.length <= 1) return 0
intervals.sort((a, b) => a[1] - b[1])
let ans = 1, backLimit = intervals[0][1]
for (let i = 1; i < intervals.length; i++) {
if (intervals[i][0] >= end) {
ans++
backLimit = intervals[i][1]
}
}
return intervals.length - ans
};
56. 合并区间
起初我还是按右边界排序,然后被[[2,3],[4,5],[6,7],[8,9],[1,10]]卡了,如果按上面的做法,前四个区间互不重叠,到第五个区间才知道,会得到错误的解,靠start = Math.min(start, intervals[i][0])也没有用。
按左边界排序,每一轮while循环都得到一个新的合并好区间,先拿出第一个区间,初始化start和end,从它的下一个区间开始,每次更新end即可。start不需要更新,因为是按左区间排序的,第一个区间的start一定最小。
var merge = function (intervals) {
intervals.sort((a, b) => a[0] - b[0]);
let start = 0,
end = 0,
i = 0;
const ans = [];
const len = intervals.length;
while (i < len) {
start = intervals[i][0];
end = intervals[i][1];
let j = i + 1;
while (j < len && intervals[j][0] <= end) {
end = Math.max(end, intervals[j][1]);
j++;
}
i = j;
ans.push([start, end]);
}
return ans;
};