План курса / Все задачи / Алгоритмы и структуры данных
Выстрелы из рогатки
средне
# решено
На полу расположены несколько воздушных шаров. Каждый i-ый шар можно расположить в отрезке points[i], где points[i][0] — начало, а points[i][1] — конец отрезка.
Петя стреляет из рогатки строго параллельно полу. Нужно найти минимальное количество выстрелов, чтобы лопнуть все шары.
Пример 1:
Ввод: points = [[1,5],[8,12],[0,3],[6,8],[7,8]]
Вывод: 2
Объяснение: Первым выстрелом сбиваем [1,5] и [0,3], а вторым [8,12],[6,8],[7,8].
Пример 2:
Ввод: points = [[2,17],[100,160]]
Вывод: 2
Ограничения:
len(points) >= 1
points можно изменять
public class Solution {
// проверяем, пересекаются ли интервалы
private static bool IsOverlapping(List<int> a, List<int> b) {
return Math.Max(a[0], b[0]) <= Math.Min(a[1], b[1]);
}
// интервалы обязательно должны пересекаться
private static List<int> OverlapTwoIntervals(List<int> a, List<int> b) {
return new List<int> { Math.Max(a[0], b[0]), Math.Min(a[1], b[1]) };
}
public static int CountShots(List<List<int>> points) {
points.Sort((a, b) => a[0].CompareTo(b[0])); // O(n * log n)
int result = 1;
List<int> lastPoint = points[0];
foreach (var point in points) {
// если интервалы пересекаются, то для них используем 1 стрелу
// и стараемся набрать как можно больше интервалов под 1 стрелу
if (IsOverlapping(lastPoint, point)) {
lastPoint = OverlapTwoIntervals(lastPoint, point);
continue;
}
// если нет пересечений, значит нужна еще 1 доп. стрела
lastPoint = point;
result++;
}
return result;
}
}
#include <vector>
#include <algorithm>
using namespace std;
// проверяем, пересекаются ли интервалы
bool isOverlapping(vector<int>& a, vector<int>& b) {
return max(a[0], b[0]) <= min(a[1], b[1]);
}
// интервалы обязательно должны пересекаться
vector<int> overlapTwoIntervals(vector<int>& a, vector<int>& b) {
return {max(a[0], b[0]), min(a[1], b[1])};
}
int countShots(vector<vector<int>>& points) {
sort(points.begin(), points.end()); // O(n * log n)
int result = 1;
vector<int> lastPoint = points[0];
for (auto& point : points) {
// если интервалы пересекаются, то для них используем 1 стрелу
// и стараемся набрать как можно больше интервалов под 1 стрелу
if (isOverlapping(lastPoint, point)) {
lastPoint = overlapTwoIntervals(lastPoint, point);
continue;
}
// если нет пересечений, значит нужна еще 1 доп стрела и обновляем
// последний интервал (lastPoint)
lastPoint = point;
result++;
}
return result;
}
package main
import (
"sort"
)
// проверяем, пересекаются ли интервалы
func isOverlapping(a, b []int) bool {
return max(a[0], b[0]) <= min(a[1], b[1])
}
// интервалы обязательно должны пересекаться
func overlapTwoIntervals(a, b []int) []int {
return []int{max(a[0], b[0]), min(a[1], b[1])}
}
func countShots(points [][]int) int {
sort.Slice(points, func(i, j int) bool {
return points[i][0] < points[j][0]
}) // O(n * log n)
result := 1
lastPoint := points[0]
for _, point := range points {
// если интервалы пересекаются, то для них используем 1 стрелу
// и стараемся набрать как можно больше интервалов под 1 стрелу
if isOverlapping(lastPoint, point) {
lastPoint = overlapTwoIntervals(lastPoint, point)
continue
}
// если нет пересечений, значит нужна еще 1 доп стрела и обновляем
// последний интервал (lastPoint)
lastPoint = point
result++
}
return result
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
import java.util.*;
public class Solution {
// проверяем, пересекаются ли интервалы
private boolean isOverlapping(List<Integer> a, List<Integer> b) {
return Math.max(a.get(0), b.get(0)) <= Math.min(a.get(1), b.get(1));
}
// интервалы обязательно должны пересекаться
private List<Integer> overlapTwoIntervals(List<Integer> a, List<Integer> b) {
List<Integer> overlap = new ArrayList<>();
overlap.add(Math.max(a.get(0), b.get(0)));
overlap.add(Math.min(a.get(1), b.get(1)));
return overlap;
}
public int countShots(List<List<Integer>> points) {
// Сортируем интервалы по начальной точке
Collections.sort(points, new Comparator<List<Integer>>() {
@Override
public int compare(List<Integer> o1, List<Integer> o2) {
return o1.get(0) - o2.get(0);
}
});
int result = 1;
List<Integer> lastPoint = points.get(0);
for (List<Integer> point : points) {
// если интервалы пересекаются, то для них используем 1 выстрел
// и стараемся набрать как можно больше интервалов под 1 выстрел
if (isOverlapping(lastPoint, point)) {
lastPoint = overlapTwoIntervals(lastPoint, point);
continue;
}
// если нет пересечений, значит нужен еще 1 выстрел и обновляем
// последний интервал (lastPoint)
lastPoint = point;
result++;
}
return result;
}
}
from typing import *
# проверяем, пересекаются ли интервалы
def is_overlapping(a: List[int], b: List[int]) -> bool:
return max(a[0], b[0]) <= min(a[1], b[1])
# интервалы обязательно должны пересекаться
def overlap_two_intervals(a: List[int], b: List[int]) -> List[int]:
return [max(a[0], b[0]), min(a[1], b[1])]
def count_shots(points: List[List[int]]) -> int:
points.sort()
result = 1
last_point = points[0]
for point in points:
# если интервалы пересекаются, то для них используем 1 выстрел
# и стараемся набрать как можно больше интервалов под 1 выстрел
if is_overlapping(last_point, point):
last_point = overlap_two_intervals(last_point, point)
continue
# если нет пересечений, значит нужна еще 1 доп выстрел и обновляем
# последний интервал (last_point)
last_point = point
result += 1
return result
// проверяем, пересекаются ли интервалы
export function isOverlapping(a, b) {
return Math.max(a[0], b[0]) <= Math.min(a[1], b[1]);
}
// интервалы обязательно должны пересекаться
export function overlapTwoIntervals(a, b) {
return [Math.max(a[0], b[0]), Math.min(a[1], b[1])];
}
export function countShots(points) {
points.sort((a, b) => a[0] - b[0]); // O(n * log n)
let result = 1;
let lastPoint = points[0];
for (let point of points) {
// если интервалы пересекаются, то для них используем 1 стрелу
// и стараемся набрать как можно больше интервалов под 1 стрелу
if (isOverlapping(lastPoint, point)) {
lastPoint = overlapTwoIntervals(lastPoint, point);
continue;
}
// если нет пересечений, значит нужна еще 1 доп стрела и обновляем
// последний интервал (lastPoint)
lastPoint = point;
result++;
}
return result;
}
Оценка сложности
Время: O(n*log(n)), где n - длина массива points
Память: O(1), при условии, что сортировка не выделяет доп.память