Skip to content

Commit 35dbfa7

Browse files
committed
Added longest range in list with sorting.
1 parent 118c406 commit 35dbfa7

File tree

3 files changed

+57
-20
lines changed

3 files changed

+57
-20
lines changed

cp_python/random_questions/calender.py renamed to cp_python/random_questions/calendar.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""
2-
For two calendars, find time periods to schedule a meeting. Each calendar is represented by a list of meetings, hence during those periods no meeting can be scheduled. Also, every calendar comes with bounds telling us the earliest and the latest we can schedule meetings.
2+
For two calendars, find time periods to schedule a meeting. Each calendar is represented by a list of meetings,
3+
hence during those periods no meeting can be scheduled. Also, every calendar comes with bounds telling us the earliest
4+
and the latest we can schedule meetings.
35
46
sample input:
57
# calendar one, meetings and bounds
@@ -13,45 +15,47 @@
1315

1416
from typing import List, Optional
1517

18+
1619
class Time:
1720
def __init__(self, time_str: str):
1821
"""Format or time_str assumed to be military: '15:30'."""
1922
self.time_str = time_str
20-
23+
2124
@property
2225
def hour(self):
2326
return int(self.time_str.split(':')[0])
24-
27+
2528
@property
2629
def minute(self):
2730
return int(self.time_str.split(':')[1])
28-
31+
2932
def __gt__(self, other):
3033
if self.hour > other.hour:
3134
return True
3235
elif self.hour == other.hour:
3336
return self.minute > other.minute
3437
elif self.hour < other.hour:
3538
return False
36-
39+
3740
def __eq__(self, other):
3841
return self.hour == other.hour and self.minute == other.minute
39-
42+
4043
def _to_hour_min(self):
4144
return [int(item) for item in self.time_str.split(':')]
42-
45+
4346
def __repr__(self):
4447
return f'Time({self.time_str})'
45-
48+
49+
4650
class Slot:
4751
def __init__(self, start: str, end: str):
4852
"""Format of arguments assumed to be military: '15:30'."""
4953
self.start = Time(start)
5054
self.end = Time(end)
51-
55+
5256
def __repr__(self):
5357
return f'{self.__class__.__name__}(start={self.start}, end={self.end})'
54-
58+
5559
def find_overlap(self, other: 'Slot') -> Optional['Slot']:
5660
slot_ahead, slot_behind = sorted([self, other], key=lambda slot: slot.start)
5761
if slot_behind.start > slot_ahead.end:
@@ -62,12 +66,13 @@ def find_overlap(self, other: 'Slot') -> Optional['Slot']:
6266
return Slot(mutual_slot_start, slot_behind.end)
6367
else:
6468
return Slot(mutual_slot_start, slot_ahead.end)
65-
66-
69+
70+
6771
class Meeting(Slot):
6872
def __init__(self, start: str, end: str):
6973
super().__init__(start, end)
70-
74+
75+
7176
class Calendar:
7277
def __init__(self, meetings: List[Meeting] = None):
7378
self.meetings = meetings if meetings else []
@@ -83,7 +88,8 @@ def free_slots(self, day_bounds: Slot):
8388
if day_bounds.end > time_ptr:
8489
free_slots.append(Slot(time_ptr.time_str, day_bounds.end.time_str))
8590
return free_slots
86-
91+
92+
8793
def find_mutual_slots(cal1: Calendar, cal2: Calendar, bounds1: Slot, bounds2: Slot) -> List[Slot]:
8894
slots1, slots2 = cal1.free_slots(bounds1), cal2.free_slots(bounds2)
8995
mutual_slots = []
@@ -94,9 +100,10 @@ def find_mutual_slots(cal1: Calendar, cal2: Calendar, bounds1: Slot, bounds2: Sl
94100
mutual_slots.append(overlap)
95101
return mutual_slots
96102

103+
97104
if __name__ == '__main__':
98-
calendar_one = Calendar([Meeting('8:00', '9:30'),
99-
Meeting('10:00', '14:00'),
105+
calendar_one = Calendar([Meeting('8:00', '9:30'),
106+
Meeting('10:00', '14:00'),
100107
Meeting('15:00', '15:30')])
101108
bounds_one = Slot("7:00", "17:30")
102109
calendar_two = Calendar([Meeting('9:00', '12:30')])

cp_python/random_questions/random_questions.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import unittest
2-
31
from data_structures.linked_list import LinkedList
42

53

@@ -100,7 +98,7 @@ def longest_range(arr: list) -> list:
10098
Idea
10199
----
102100
1) We could sort the array and then go through it and check for consecutive ranges easily.
103-
However, sorting takes O(nlogn), n being len(arr), while space would be O(1)
101+
However, sorting takes O(nlogn), n being len(arr), while space would be O(1) - see trivial below
104102
2) We can store the whole arr in marked - hash table, initialized with False for every entry.
105103
Then we would go through the array and take each position as a starting point to explore ranges
106104
in both directions if this starting point has not been marked yet. We keep track of our longest
@@ -142,3 +140,34 @@ def longest_range(arr: list) -> list:
142140
return [largest_low, largest_high]
143141

144142

143+
def longest_range_with_sorting(arr: list) -> list:
144+
"""For problem description see longest_range."""
145+
if len(arr) == 0:
146+
return [None, None]
147+
148+
arr = sorted(arr)
149+
largest_length = 1
150+
low, high = arr[0], arr[0]
151+
152+
jumped = False
153+
current_length = 1
154+
current_low = low
155+
current_high = high
156+
for idx in range(len(arr) - 1):
157+
if jumped:
158+
current_length = 1
159+
current_low = arr[idx]
160+
current_high = arr[idx]
161+
jumped = False
162+
if arr[idx + 1] == arr[idx] + 1:
163+
current_length += 1
164+
current_high = arr[idx + 1]
165+
else:
166+
jumped = True
167+
if jumped or idx + 1 == (len(arr) - 1):
168+
if current_length > largest_length:
169+
low = current_low
170+
high = current_high
171+
largest_length = current_length
172+
173+
return [low, high]

cp_python/tests/random_questions/test_random_questions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from random_questions.random_questions import add_one_to_digit_list
44
from random_questions.random_questions import reverse_linked_list, reverse_linked_list_2
55
from random_questions.random_questions import schnecken_dist_travelled
6-
from random_questions.random_questions import longest_range
6+
from random_questions.random_questions import longest_range, longest_range_with_sorting
77
from data_structures.linked_list import LinkedList
88
from tests.test_utils import run_sub_tests
99

@@ -41,4 +41,5 @@ def test_longest_range(self):
4141
for test_idx, (in_arr, solution) in enumerate(test_cases):
4242
with self.subTest(test_idx=test_idx):
4343
self.assertEqual(solution, longest_range(in_arr))
44+
self.assertEqual(solution, longest_range_with_sorting(in_arr))
4445

0 commit comments

Comments
 (0)