Day30| 452. 用最少数量的箭引爆气球、435. 无重叠区间、763.划分字母区间
文章链接
重叠区间问题
452. 用最少数量的箭引爆气球
思路:
-
如果没有气球,不需要箭引爆
-
对所有气球的长度起点进行排序
-
遍历气球,如果气球的起点大于上一个气球的终点,还需要一支箭;反之,取前两个气球的终点的最小是,继续循环
public class Solution {public int FindMinArrowShots(int[][] points) {if(points.Length==0) return 0;Array.Sort(points,(a,b)=>a[0].CompareTo(b[0]));int count=1;for(int i=1;i<points.Length;i++){if(points[i][0]>points[i-1][1]) count++;else points[i][1]=Math.Min(points[i][1],points[i-1][1]);}return count;}
}
435. 无重叠区间
左边界或右边界排序都可以,思路同上题
假设左排序:
-
首先对集合的左边界进行排序
-
遍历集合,如果某元素的左边界大于上一个元素的右边界,没有重叠了;反之,某元素的左边界小于上一个元素的右边界,重叠了,count++
思路:
- 先排序: 把所有区间按起始时间升序排序(
Array.Sort(intervals, (a, b) => a[0].CompareTo(b[0])
))。
这样可以让我们线性扫描每个区间,逐个比较当前和上一个区间是否重叠。
-
设置指针
preEnd
: 用变量preEnd
表示当前保留下来的区间的结束时间,初始为第一个区间的结束时间。 -
遍历判断重叠:
-
如果当前区间的开始时间
< preEnd
,说明发生了重叠,要删除其中一个。 -
贪心策略:留下结束时间早的那个(更早结束 → 更有可能与后面区间不重叠)。
-
所以更新
preEnd = Math.Min(preEnd, intervals[i][1])
-
同时
count++
,记录需要删除的数量。 -
如果不重叠,说明可以保留当前区间,更新
preEnd = intervals[i][1]
。
public class Solution {public int EraseOverlapIntervals(int[][] intervals) {if (intervals.Length == 0) return 0;Array.Sort(intervals,(a,b)=>a[0].CompareTo(b[0]));int count=0;int preEnd=intervals[0][1];// 第一个区间结束时间for(int i=1;i<intervals.Length;i++){// 重叠了,必须删除其中一个,留下结束更早的if(intervals[i][0]<preEnd){count++;preEnd=Math.Min(preEnd,intervals[i][1]);}else{ // 没有重叠,更新 preEnd 为当前区间的结束preEnd=intervals[i][1];}}return count;}
}
763.划分字母区间
思路:寻找最远出现的位置
-
创建一个长度为27的数组,用于记录每个小写字母最后一次出现的位置,存于location数组中
-
创建left、right,遍历字符串,用right记录当前片段中所有字符的最远位置
-
一旦下标i到达right,断开,把righ-left+1加入结果res中,重新设置left=i+1;
public class Solution {public IList<int> PartitionLabels(string s) {int[] location=new int[27];for(int i=0;i<s.Length;i++){location[s[i]-'a']=i;}List<int> res=new List<int>();int left=0,right=0;for(int i=0;i<s.Length;i++){right=Math.Max(location[s[i]-'a'],right);if(i==right){res.Add(right-left+1);left=i+1;}}return res;}
}