452. 用最少数量的箭引爆气球 - 力扣(LeetCode)
先根据气球左边界从小到大排序,然后从左往右遍历,需要维护当前区间最小右边界。
写法一:用while循环,不过边界判断和i更新的位置容易出错。当气球的左边界不大于区间右边界,更新右边界end,i增加1;否则,箭的数量增加1。
class Solution:
def findMinArrowShots(self, points) -> int:
points.sort(key = lambda x: x[0])
i = 0
cnt = 0
while i < len(points):
end = points[i][1]
i += 1
while i < len(points) and points[i][0] <= end:
end = min(end, points[i][1])
i += 1
cnt += 1
return cnt
写法二:for循环遍历points,将当前元素的右边界改为区间右边界,每次判断元素左边界与上一个元素的有边界即可。
class Solution:
def findMinArrowShots(self, points) -> int:
points.sort(key = lambda x: x[0])
cnt = 1
for i in range(1, len(points)):
if points[i][0] > points[i-1][1]:
cnt += 1
else:
points[i][1] = min(points[i][1], points[i-1][1])
return cnt
首先按左边界从小到大将区间排序,接着遍历一次数组,若上一个区间与当前区间不重合,不需要处理;若重合,删掉右边界更靠右的区间(cnt增1),修改当前区间的右边界为更靠左的右边界(因为更靠右的已经删掉了)。
class Solution:
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
intervals.sort(key = lambda x: x[0])
cnt = 0
for i in range(1, len(intervals)):
if intervals[i-1][1] > intervals[i][0]:
intervals[i][1] = min(intervals[i][1], intervals[i-1][1])
cnt += 1
return cnt
解法一:与上面两题思路类似,首先耗费O(1)的空间统计字符串中各字母所在区间:[首次出现位置,最后出现位置],接着按左边界从小到大排序,用left和right维护当前区间的左右边界,若当前字母区间在上一个区间之外,即right<该字母开始位置,就将上一个区间长度推入res,更新left和right为当前字母的左右边界;若当前字母与上一区间重合,需要合并两区间:将right更新为上一区间右界和当前字母右界的较大值。循环结束还有最后一个区间未入res,加入。
易错1:统计时,当第一次遇到一个字母,应该将其右边界也初始化为左边界的值,因为它可能只出现一次。
易错2:通过上一区间右界right判断是否重叠,right更新时也是取自身和当前右界的最大值,而不是考虑上个字母的右界values[i-1][1]。
class Solution:
def partitionLabels(self, s: str) -> List[int]:
interval = dict()
for i in range(len(s)):
c = s[i]
try:
interval[c][1] = i
except KeyError:
interval[c] = [i, i]
values = list(interval.values())
values.sort(key = lambda x: x[0])
res = []
left = 0
right = values[0][1]
for i in range(1, len(values)):
if right < values[i][0]:
res.append(right-left+1)
left = values[i][0]
right = values[i][1]
else:
right = max(values[i][1], right)
res.append(right-left+1)
return res
解法二:用字典保存字母最后出现位置,遍历s,用当前字母最后位置更新区间右界right,若当前下标等于区间右界,说明得到了一个区间,将长度推入res。
class Solution:
def partitionLabels(self, s: str) -> List[int]:
interval = dict()
for i, c in enumerate(s):
interval[c] = i
left = 0
right = interval[s[0]]
res = []
for i, c in enumerate(s):
right = max(right, interval[c])
if right == i:
res.append(right-left+1)
left = i + 1
return res