План курса / Все задачи / Алгоритмы и структуры данных
Слияние отрезков
средне
# решено
Дан массив отрезков segments, где каждый отрезок представлен в виде [начало, конец]. Нужно объединить все пересекающиеся отрезки и вернуть массив непересекающихся отрезков, отсортированных по возрастанию.
Отрезки считаются пересекающимися, если у них есть хотя бы одна общая точка.
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> MergeTwoSegments(List<int> a, List<int> b)
{
// Интервалы обязательно должны пересекаться
return new List<int> { a[0], Math.Max(a[1], b[1]) };
}
// Основная функция для объединения интервалов
public static List<List<int>> Merge(List<List<int>> segments)
{
// Сортируем интервалы по начальной точке
segments.Sort((a, b) => a[0].CompareTo(b[0]));
List<List<int>> result = new List<List<int>>();
result.Add(segments[0]);
for (int i = 1; i < segments.Count; i++)
{
List<int> segment = segments[i];
// Если текущий интервал и последний в ответе пересекаются,
// значит объединяем их, иначе добавляем интервал к ответу
if (IsOverlapping(result[result.Count - 1], segment))
{
result[result.Count - 1] = MergeTwoSegments(result[result.Count - 1], segment);
}
else
{
result.Add(segment);
}
}
return result;
}
}
#include <vector>
#include <algorithm>
using namespace std;
bool isOverlapping(const vector<int>& a, const vector<int>& b) {
return max(a[0], b[0]) <= min(a[1], b[1]);
}
vector<int> mergeTwoSegments(const vector<int>& a, const vector<int>& b) {
// интервалы обязательно должны пересекаться
return {a[0], max(a[1], b[1])};
}
vector<vector<int>> merge(vector<vector<int>>& segments) {
sort(segments.begin(), segments.end());
vector<vector<int>> result;
result.push_back(segments[0]);
for (int i = 1; i < segments.size(); i++) {
const vector<int>& segment = segments[i];
// если текущий интервал и последний в ответе пересекаются,
// значит объединяем их, иначе добавляем интервал к ответу
if (isOverlapping(result.back(), segment)) {
result.back() = mergeTwoSegments(result.back(), segment);
} else {
result.push_back(segment);
}
}
return result;
}
package main
import (
"sort"
)
func isOverlapping(a, b []int) bool {
return max(a[0], b[0]) <= min(a[1], b[1])
}
func mergeTwoSegments(a, b []int) []int {
// интервалы обязательно должны пересекаться
return []int{a[0], max(a[1], b[1])}
}
func merge(segments [][]int) [][]int {
sort.Slice(segments, func(i, j int) bool {
return segments[i][0] < segments[j][0]
})
result := [][]int{segments[0]}
for i := 1; i < len(segments); i++ {
segment := segments[i]
// если текущий интервал и последний в ответе пересекаются,
// значит объединяем их, иначе добавляем интервал к ответу
if isOverlapping(result[len(result)-1], segment) {
result[len(result)-1] = mergeTwoSegments(result[len(result)-1], segment)
} else {
result = append(result, segment)
}
}
return result
}
import java.util.*;
public class Solution {
public 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));
}
public List<Integer> mergeTwoSegments(List<Integer> a, List<Integer> b) {
// интервалы обязательно должны пересекаться
return Arrays.asList(a.get(0), Math.max(a.get(1), b.get(1)));
}
public List<List<Integer>> merge(List<List<Integer>> segments) {
segments.sort((a, b) -> Integer.compare(a.get(0), b.get(0)));
List<List<Integer>> result = new ArrayList<>();
result.add(segments.get(0));
for (int i = 1; i < segments.size(); i++) {
List<Integer> segment = segments.get(i);
// если текущий интервал и последний в ответе пересекаются,
// значит объединяем их, иначе добавляем интервал к ответу
if (isOverlapping(result.get(result.size() - 1), segment)) {
result.set(result.size() - 1, mergeTwoSegments(result.get(result.size() - 1), segment));
} else {
result.add(segment);
}
}
return result;
}
}
from typing import *
def is_overlapping(a: int, b: int) -> bool:
return max(a[0], b[0]) <= min(a[1], b[1])
def merge_two_segments(a: int, b: int) -> List[int]:
# интервалы обязательно должны пересекаться
return [a[0], max(a[1], b[1])]
def merge(segments: List[List[int]]) -> List[List[int]]:
segments.sort()
result = []
result.append(segments[0])
for i in range(1, len(segments)):
segment = segments[i]
# если текущий интервал и последний в ответе пересекаются,
# значит объединяем их, иначе добавляем интервал к ответу и это значит,
# что ни один интервал, который имеет точку начала меньше текущего интервала
# не будет пересечен ни с одним лежащим правее и не с текущим
if is_overlapping(result[-1], segment):
result[-1] = merge_two_segments(result[-1], segment)
else:
result.append(segment)
return result
function isOverlapping(a, b) {
return Math.max(a[0], b[0]) <= Math.min(a[1], b[1]);
}
function mergeTwoSegments(a, b) {
// интервалы обязательно должны пересекаться
return [a[0], Math.max(a[1], b[1])];
}
export function merge(segments) {
segments.sort((a, b) => a[0] - b[0]);
const result = [];
result.push(segments[0]);
for (let i = 1; i < segments.length; i++) {
const segment = segments[i];
// если текущий интервал и последний в ответе пересекаются,
// значит объединяем их, иначе добавляем интервал к ответу и это значит,
// что ни один интервал, который имеет точку начала меньше текущего интервала
// не будет пересечен ни с одним лежащим правее и не с текущим
if (isOverlapping(result[result.length - 1], segment)) {
result[result.length - 1] = mergeTwoSegments(result[result.length - 1], segment);
} else {
result.push(segment);
}
}
return result;
}
Оценка сложности
Время: O(n*log(n)), где n - длина массива segments