给定一个区间的集合 intervals
,其中 intervals[i] = [starti, endi]
。返回 需要移除区间的最小数量,使剩余区间互不重叠 。
示例 1:
输入: intervals = [[1,2],[2,3],[3,4],[1,3]] 输出: 1 解释: 移除 [1,3] 后,剩下的区间没有重叠。
示例 2:
输入: intervals = [ [1,2], [1,2], [1,2] ] 输出: 2 解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。
示例 3:
输入: intervals = [ [1,2], [2,3] ] 输出: 0 解释: 你不需要移除任何区间,因为它们已经是无重叠的了。
提示:
1 <= intervals.length <= 105
intervals[i].length == 2
-5 * 104 <= starti < endi <= 5 * 104
依旧是区间问题,和上一天的气球那题差不多。本题要求移除最少的区间,使剩下的 区间之间互不重叠。并且 [ 1, 2 ] 和 [ 2, 3 ] 这样边缘接触的区间不算重叠。
首先依旧要先对区间进行排序,按区间的起点进行升序排序,相同起点的区间按终点进行升序排序。
本题的本质依旧是求相邻区间之间的重叠区域,当然这个相邻不只是指两个区间,比如有可能连续的三个区间都存在共同的重叠区域。又因为已经将区间排序了,所以只需要获取重叠区域的右端点进行判断。
设置一个变量 end 为重叠区域的右端点,初始值为第一个区间的右端点,即先设置第一个区间为重叠区域,先遍历到下一个区间判断其与上一个区间是否存在重叠区域,存在则删除区间数 + 1,且 end 变为新的重叠区域的右端点;不存在 end 则变为当前区间的右端点。
function eraseOverlapIntervals($intervals) {
usort($intervals, function($a, $b) {
if($a[0] == $b[0]) return $a[1] > $b[1];
return $a[0] > $b[0];
});
$sum = 0;
$end = $intervals[0][1];
for($i = 1; $i < count($intervals); $i++) {
if($end > $intervals[$i][0]) {
$sum++;
$end = min($intervals[$i][1], $end);
} else {
$end = $intervals[$i][1];
}
}
return $sum;
}
给你一个字符串 s
。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s
。
返回一个表示每个字符串片段的长度的列表。
示例 1:
输入:s = "ababcbacadefegdehijhklij" 输出:[9,7,8] 解释: 划分结果为 "ababcbaca"、"defegde"、"hijhklij" 。 每个字母最多出现在一个片段中。 像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。
示例 2:
输入:s = "eccbbbbdec" 输出:[10]
提示:
1 <= s.length <= 500
s
仅由小写英文字母组成这道题一开始根本没有思路,去看了题解才恍然还有这种解法。了解后发现这道题和之前的跳跃问题有点相像,本质上都是求当前的最远范围。
先把字符串遍历一遍,获取字符串中出现过的字母在字符串中最后出现的位置,即最远位置。
要把字符串划分为多个片段,且同一字母最多出现在一个片段内。所以拿到每个字母的最远位置,我们就明确了切割点。
但还有一个问题待解决,字母之间是交叉在一起的,比如包含全部 ' a ' 的片段中还包含了 ' b ',但是 ' b '字母不止出现在这个片段中。例如:' aababb',划分为 ' aaba ' 显然是错误的。
所以遍历字符串时,切割点是一直在变的,切割点应该是当前遍历过的所有字母中最大的最远位置,例如上面举例的 ' aababb',b 的最远位置比 a 的大,所以切割点不应该是 a 的最远位置。直到到达切割点 i 所在的第 i 个位置,才可以进行切割,然后遍历下一个字母,找到新的切割点。
function partitionLabels($s) {
$used = [];
for($i = 0; $i < strlen($s); $i++) {
$used[$s[$i]] = $i;
}
$max = -1;
$cur = 0;
$res = [];
for($i = 0; $i < strlen($s); $i++) {
$max = max($used[$s[$i]], $max);
if($max == $i) {
$res[] = $i - $cur + 1;
$cur = $i + 1;
$max = -1;
}
}
return $res;
}
以数组 intervals
表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]] 解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]] 输出:[[1,5]] 解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
提示:
1 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 104
本题依旧是区间问题,但和之前的题目不一样的是,之前的题目都是通过获取重叠区域来进行比较,也就是求重叠区间之间的交集。但本题是合并重叠的区间,也就是求重叠区间的并集。
所以变量 end 就要改变含义,从交集区域的右端点,变为并集区间的右端点。而其他逻辑和之前的区间题目差不多。
但和上面的 '无重叠区间' 题目还有一点不同,本题定义的重叠包括边缘相触的区间,例如 [ 1, 2 ] 和 [ 2, 3 ]。
function merge($intervals) {
usort($intervals, function($a, $b) {
if($a[0] == $b[0]) return $a[1] > $b[1];
return $a[0] > $b[0];
});
$start = $intervals[0][0];
$end = $intervals[0][1];
$res = [];
for($i = 1; $i < count($intervals); $i++) {
if($end >= $intervals[$i][0]) {
$end = max($intervals[$i][1], $end);
} else {
$res[] = [$start, $end];
$start = $intervals[$i][0];
$end = $intervals[$i][1];
}
}
$res[] = [$start, $end];
return $res;
}