Enable Javascript in your browser and then refresh this page, for a much enhanced experience.
Operating cut solution in Clear category for Lightbulb Operating by Phil15
from datetime import datetime, timedelta
from itertools import zip_longest
from typing import Dict, Iterable, List, Optional, Tuple, Union
Interval = Tuple[datetime, datetime]
def cut(intervals: Iterable[Interval], operating: datetime) -> Iterable[Interval]:
for start, end in intervals:
end = min(end, start + operating)
yield start, end
operating -= end - start
if not operating:
break
def sum_light(
els: List[Union[datetime, Tuple[datetime, int]]],
start_watching: datetime = datetime.min,
end_watching: datetime = datetime.max,
operating: Optional[timedelta] = None,
) -> float:
# List timelines for each "light id".
timelines: Dict[int, List[datetime]] = {}
for elem in els:
if isinstance(elem, datetime):
light_id = 1
else:
elem, light_id = elem
timelines.setdefault(light_id, []).append(elem)
# List intervals of light, cut according to operating, merge them.
intervals = sorted(
interval
for timeline in timelines.values()
for _intervals in [
(
(max(start_watching, start), min(end_watching, end))
for start, end in zip_longest(
timeline[::2], timeline[1::2], fillvalue=end_watching
)
if start < end_watching and end > start_watching
)
]
for interval in (
_intervals if operating is None else cut(_intervals, operating)
)
)
return sum(
(end - start).total_seconds()
for start, end in merge_intervals(intervals)
)
def merge_intervals(intervals): # Note that it take sorted intervals.
res = []
for start, end in intervals:
if res and start <= res[~0][1]:
res[~0][1] = max(res[~0][1], end)
else:
res.append([start, end])
return res
Dec. 8, 2021