这是跟着代码随想录的顺序学习算法的第?天。
以下是学习时自己的一些理解与笔记,如有错误欢迎指正与讨论。
435. 无重叠区间
参考相关链接:
笔记
自己做本题时候的思路是,是想着用双指针法,于是先按元素的左边界进行排序,用 left
指针指向上一个最近的没有被移除的元素,用 right
指针指向最新的未比较元素(也就是用来遍历数组的一个指针)。
当 left
指向的区间与 right
指向的区间重叠的时候,需要移除其中的一个。
此时,我们拿到的数组是已经按左边界排序过了的,也就是说,left
前面的未移除元素是比 left
小的,再换句话说,是对当前的 left
以及之后的元素没有影响的。
所以,为了达到上面的效果,我们应该将两个区间中右边界更大的区间移除掉。
事实上,就算是不从上面的路径进行思考,当问及自己应该删除哪个区间的时候,我们依旧会很自然地期望将右边界更大的区间移除掉;当进一步问自己为什么这么做的时候,"因为右边的区间还没判断完,为了减小对后面区间的影响呗"之类的话便可能不经意间脱口而出。
其实,这也就是贪心思想,用局部最优推出全局最优,在现在的角度出发,想法设法地去为了后面的工作更方便地达到目标而进行现在的处理,对后面区间的影响越小,也就越有可能不用消除区间,也就是需要消除的区间数越少。
后面看卡哥的题解的时候发现,其实卡哥的解法也可也从双指针的角度去切入理解,慢指针是 end
,快指针是 i
,接着,用贪心的思想去做进一步的处理。只不过卡哥在这里是直接就从贪心角度切入的,也更符合所在的章节主题。
// 自己做的
var eraseOverlapIntervals = function(intervals) {
let res = 0;
intervals.sort((a, b) => a[0] - b[0]);
let left = 0, right = 1; // right 指向最新的, left 指向上一个没有被移除的元素
for(; right < intervals.length; right++) {
// 遇到重叠 移除大范围 范围一样大移除后者
if(intervals[right][0] < intervals[left][1]) {
if(intervals[left][1] > intervals[right][1]) {
// 移除前者
left = right;
}
// 移除后者 不用操作
res++;
} else {
left = right; // 修改下一次对比的区间
}
}
return res;
};
// 代码随想录JS版本
var eraseOverlapIntervals = function(intervals) {
intervals.sort((a, b) => {
return a[1] - b[1]
})
let count = 1
let end = intervals[0][1]
for(let i = 1; i < intervals.length; i++) {
let interval = intervals[i]
if(interval[0] >= end) {
end = interval[1]
count += 1
}
}
return intervals.length - count
};