diff --git a/DIRECTORY.md b/DIRECTORY.md index d2957aa6..eae3cf76 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -101,6 +101,8 @@ * [Decoding](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/huffman/decoding.py) * [Encoding](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/huffman/encoding.py) * Intervals + * Count Days + * [Test Count Days Without Meetings](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/intervals/count_days/test_count_days_without_meetings.py) * Insert Interval * [Test Insert Interval](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/intervals/insert_interval/test_insert_interval.py) * Interval Intersection diff --git a/algorithms/intervals/count_days/README.md b/algorithms/intervals/count_days/README.md new file mode 100644 index 00000000..668fc1b3 --- /dev/null +++ b/algorithms/intervals/count_days/README.md @@ -0,0 +1,65 @@ +# Count Days Without Meetings + +You are given a positive integer, `days`, which represents the total number of days an employee is available for work, +starting from day 1. You are also given a 2D array, `meetings`, where each entry meetings[i] = [starti, endi] indicates +that a meeting is scheduled from day starti to day endi (both inclusive). + +Your task is to count the days when the employee is available for work but has no scheduled meetings. + +> Note: The meetings may overlap. + +## Constraints + +- 1 <= days <= 10^5 +- 1 <= meetings.length <= 10^3 +- meetings[i].length == 2 +- 1 <= `meetings[i][0]` <= `meetings[i][1]` <= days + +## Examples + +![Example 1](./images/examples/count_days_without_meetings_example_1.png) +![Example 2](./images/examples/count_days_without_meetings_example_2.png) +![Example 3](./images/examples/count_days_without_meetings_example_3.png) + +## Solution + +The core idea of this solution is to merge overlapping meetings into continuous intervals to efficiently track the +occupied days. We begin by sorting the meetings to process them sequentially. As we iterate, we merge overlapping +meetings while counting the occupied days whenever gaps appear. Finally, subtracting the total occupied days from the +available days gives the number of free days. + +Using the intuition above, we implement the algorithm as follows: + +1. First, sort the meetings based on their start time to process them in order. +2. Initialize a variable, occupied, with 0 to count the days when the employee has scheduled meetings. +3. Initialize two variables, start and end, with the first meeting’s start and end times. These variables define the + beginning and end of the merged meeting interval to efficiently track continuously occupied periods. +4. Iterate through the remaining meetings: + - If a meeting overlaps with the current merged meeting, extend the end time to merge it into the existing interval. + - Otherwise, add the days of the merged meeting to occupied as `occupied = occupied + (end - start + 1)`. Then, update + the start and end for the next interval. +5. After the loop, add the days of the last merged interval to occupied. +6. Return the difference between days and occupied (`days−occupied`), representing the number of days when the employee + is available for work but has no scheduled meetings. + +![Solution 1](./images/solutions/count_days_without_meetings_solution_1.png) +![Solution 2](./images/solutions/count_days_without_meetings_solution_2.png) +![Solution 3](./images/solutions/count_days_without_meetings_solution_3.png) +![Solution 4](./images/solutions/count_days_without_meetings_solution_4.png) +![Solution 5](./images/solutions/count_days_without_meetings_solution_5.png) +![Solution 6](./images/solutions/count_days_without_meetings_solution_6.png) +![Solution 7](./images/solutions/count_days_without_meetings_solution_7.png) +![Solution 8](./images/solutions/count_days_without_meetings_solution_8.png) +![Solution 9](./images/solutions/count_days_without_meetings_solution_9.png) +![Solution 10](./images/solutions/count_days_without_meetings_solution_10.png) +![Solution 11](./images/solutions/count_days_without_meetings_solution_11.png) +![Solution 12](./images/solutions/count_days_without_meetings_solution_12.png) + +### Time Complexity + +The algorithm’s time complexity is O(nlogn), where n is the size of the meetings array. This is due to the sorting step, +which dominates the overall complexity while merging the intervals runs in O(n). + +### Space Complexity + +The algorithm’s space complexity is constant, O(1). diff --git a/algorithms/intervals/count_days/__init__.py b/algorithms/intervals/count_days/__init__.py new file mode 100644 index 00000000..a820db5e --- /dev/null +++ b/algorithms/intervals/count_days/__init__.py @@ -0,0 +1,110 @@ +from typing import List + + +def count_days(days: int, meetings: List[List[int]]) -> int: + """ + Counts the number of days the employee is available for work but has no scheduled meetings. + + Complexity: + + Standard time complexity for sorting is O(n log(n)). The loop is O(n). The part that dominates the overall time + complexity is the sorting and the loop. It amounts to O(n log(n)) as the overall. The overall space complexity for + this approach is O(1) without accounting for the in place sorting that is taking place which is O(n) using timsort + in Python. + + Summary of Performance + --- + Metric Complexity Reason + --- + Time O(nlogn) Dominated by the initial sort of n meetings. + Space O(n) Required by Timsort for internal temporary storage. + + Args: + days (int): The total number of days the employee is available for work + meetings (List[List[int]]): A list of meetings, where each meeting is represented as a list of two integers [start, end] + Returns: + int: The number of days the employee is available for work but has no scheduled meetings + """ + # sort meetings by start in place, incurs O(n log(n)) time complexity + meetings.sort(key=lambda x: x[0]) + + # keep track of free days + free_days = 0 + + # a pointer that keeps track of the current day + last_busy_day = 0 + + # iterate through the meetings, for each meeting we might have a gap + for meeting in meetings: + # get the start and end of the meeting + start, end = meeting + + # calculate gaps, if the meeting starts at start and our last_busy_day is less than start - 1, the days in + # between are free + if start > last_busy_day + 1: + free_days += (start - 1) - last_busy_day + + # update the last busy day to the maximum of the last busy day and the end of the meeting + + # This ensures that if a meeting is completely contained within a previous busy block, the boundary doesn't move + # backward, which handles overlaps perfectly. + last_busy_day = max(last_busy_day, end) + + # add the remaining days to the free days + return free_days + (days - last_busy_day) + + +def count_days_2(days: int, meetings: List[List[int]]) -> int: + """ + Counts the number of days the employee is available for work but has no scheduled meetings. + + This implementation merges overlapping meetings and counts total occupied days. + + Time Complexity: O(n log n) due to sorting + Space Complexity: O(1) excluding sort overhead + + Args: + days (int): The total number of days the employee is available for work + meetings (List[List[int]]): A list of meetings, where each meeting is represented as a list of two integers [start, end] + Note: This function modifies the input list by sorting it in place. + Returns: + int: The number of days the employee is available for work but has no scheduled meetings + """ + # Sort the meetings based on their start time to process them in order + meetings.sort() + + # Initialize a variable with 0 to count the number of days when the employee has meetings scheduled + occupied = 0 + + # Initialize two variables with the first meeting’s start and end times + # Sort the meetings based on their start time to process them in order + meetings.sort() + + # Handle edge case of empty meetings + if not meetings: + return days + + # Initialize a variable with 0 to count the number of days when the employee has meetings scheduled + occupied = 0 + + # Initialize two variables with the first meeting's start and end times + start, end = meetings[0] + + # Iterate through the remaining meetings + for i in range(1, len(meetings)): + # If a meeting overlaps with the current merged meeting + if meetings[i][0] <= end: + # Extend the end time to merge it + end = max(end, meetings[i][1]) + else: + # Add the days of the merged meeting + occupied += end - start + 1 + + # Update start and end for the next interval + start, end = meetings[i] + + # Add the days of the last merged meeting + occupied += end - start + 1 + + # Return the free days + return days - occupied diff --git a/algorithms/intervals/count_days/images/examples/count_days_without_meetings_example_1.png b/algorithms/intervals/count_days/images/examples/count_days_without_meetings_example_1.png new file mode 100644 index 00000000..561f78aa Binary files /dev/null and b/algorithms/intervals/count_days/images/examples/count_days_without_meetings_example_1.png differ diff --git a/algorithms/intervals/count_days/images/examples/count_days_without_meetings_example_2.png b/algorithms/intervals/count_days/images/examples/count_days_without_meetings_example_2.png new file mode 100644 index 00000000..338dd8c3 Binary files /dev/null and b/algorithms/intervals/count_days/images/examples/count_days_without_meetings_example_2.png differ diff --git a/algorithms/intervals/count_days/images/examples/count_days_without_meetings_example_3.png b/algorithms/intervals/count_days/images/examples/count_days_without_meetings_example_3.png new file mode 100644 index 00000000..a224306d Binary files /dev/null and b/algorithms/intervals/count_days/images/examples/count_days_without_meetings_example_3.png differ diff --git a/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_1.png b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_1.png new file mode 100644 index 00000000..d62d3914 Binary files /dev/null and b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_1.png differ diff --git a/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_10.png b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_10.png new file mode 100644 index 00000000..5635cf3c Binary files /dev/null and b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_10.png differ diff --git a/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_11.png b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_11.png new file mode 100644 index 00000000..b4fb5d0e Binary files /dev/null and b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_11.png differ diff --git a/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_12.png b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_12.png new file mode 100644 index 00000000..4e1f4ad2 Binary files /dev/null and b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_12.png differ diff --git a/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_2.png b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_2.png new file mode 100644 index 00000000..6fa16744 Binary files /dev/null and b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_2.png differ diff --git a/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_3.png b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_3.png new file mode 100644 index 00000000..dcb2863e Binary files /dev/null and b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_3.png differ diff --git a/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_4.png b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_4.png new file mode 100644 index 00000000..556d6e4c Binary files /dev/null and b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_4.png differ diff --git a/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_5.png b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_5.png new file mode 100644 index 00000000..7db54094 Binary files /dev/null and b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_5.png differ diff --git a/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_6.png b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_6.png new file mode 100644 index 00000000..80c0454a Binary files /dev/null and b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_6.png differ diff --git a/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_7.png b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_7.png new file mode 100644 index 00000000..7d4303dd Binary files /dev/null and b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_7.png differ diff --git a/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_8.png b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_8.png new file mode 100644 index 00000000..15bcf014 Binary files /dev/null and b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_8.png differ diff --git a/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_9.png b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_9.png new file mode 100644 index 00000000..bfebf29f Binary files /dev/null and b/algorithms/intervals/count_days/images/solutions/count_days_without_meetings_solution_9.png differ diff --git a/algorithms/intervals/count_days/test_count_days_without_meetings.py b/algorithms/intervals/count_days/test_count_days_without_meetings.py new file mode 100644 index 00000000..f2548b20 --- /dev/null +++ b/algorithms/intervals/count_days/test_count_days_without_meetings.py @@ -0,0 +1,525 @@ +import unittest +from typing import List +from parameterized import parameterized +from algorithms.intervals.count_days import count_days, count_days_2 + +TEST_CASES = [ + (10, [[7, 9], [3, 6]], 3), + (100, [[1, 100]], 0), + (12, [[10, 12], [1, 5], [4, 8]], 1), + (12, [[5, 6], [9, 11], [1, 3]], 4), + (6, [[2, 4], [5, 5]], 2), + (100000, [[1, 100000]], 0), + (3136, [[361, 570], [420, 1225], [72, 144], [987, 1444]], 1979), + (786, [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]], 774), + ( + 54474, + [ + [1646, 1745], + [8226, 8322], + [350, 457], + [27725, 27748], + [14424, 14509], + [31944, 32009], + [8971, 9017], + [684, 772], + [21549, 21619], + [31929, 31971], + [23892, 23955], + [19487, 19526], + [22921, 22957], + [17253, 17308], + [18454, 18535], + [20151, 20154], + [3183, 3285], + [20204, 20254], + [15794, 15879], + [9624, 9653], + [20922, 21004], + [20841, 20871], + [26184, 26265], + [8312, 8373], + [20521, 20621], + [21159, 21206], + [33908, 33970], + [7775, 7798], + [13420, 13476], + [18464, 18537], + [1780, 1805], + [33435, 33531], + [7344, 7347], + [20990, 21102], + [23930, 23987], + [33244, 33351], + [8764, 8766], + [25020, 25053], + [5043, 5101], + [8575, 8621], + [11443, 11526], + [1960, 2061], + [15120, 15225], + [19825, 19857], + [22747, 22754], + [5122, 5210], + [10072, 10087], + [28172, 28284], + [6259, 6359], + [28800, 28812], + [21174, 21271], + [17472, 17529], + [30661, 30755], + [25555, 25654], + [3942, 4050], + [15547, 15627], + [33434, 33486], + [13205, 13221], + [28666, 28738], + [16682, 16751], + [30500, 30524], + [16278, 16290], + [29038, 29061], + [21498, 21503], + [6467, 6530], + [25366, 25410], + [15900, 16008], + [18221, 18299], + [30929, 30957], + [4568, 4609], + [30462, 30522], + [34492, 34526], + [2259, 2270], + [19369, 19452], + [1888, 1989], + [12254, 12260], + [17861, 17914], + [31687, 31710], + [32534, 32576], + [22006, 22031], + [25541, 25622], + [22168, 22257], + [12733, 12832], + [8226, 8226], + [9279, 9313], + [26989, 27086], + [10495, 10523], + [10509, 10618], + [11623, 11723], + [12437, 12500], + [662, 746], + [28486, 28596], + [8987, 9087], + [23676, 23710], + [6104, 6159], + [31947, 31997], + [3502, 3561], + [5550, 5617], + [17326, 17341], + [10278, 10285], + [4291, 4323], + [34537, 34644], + [4742, 4844], + [27462, 27566], + [8274, 8288], + [2160, 2196], + [3645, 3746], + [3805, 3848], + [21291, 21354], + [12913, 13004], + [7303, 7383], + [32195, 32300], + [27748, 27777], + [1579, 1592], + [8442, 8475], + [34076, 34163], + [23251, 23325], + [31714, 31735], + [31004, 31012], + [1720, 1744], + [31266, 31321], + [6903, 7008], + [19604, 19610], + [34505, 34508], + [1579, 1655], + [1279, 1294], + [13407, 13429], + [33781, 33807], + [27537, 27604], + [25418, 25528], + [5044, 5097], + [15345, 15391], + [19108, 19150], + [13736, 13759], + [16366, 16368], + [12600, 12698], + [9897, 9905], + [20693, 20747], + [22241, 22242], + [2113, 2169], + [10777, 10796], + [10637, 10716], + [9424, 9506], + [22735, 22774], + [22305, 22414], + [32819, 32870], + [27991, 27993], + [13558, 13618], + [7561, 7610], + [31890, 31900], + [7933, 7943], + [18311, 18403], + [622, 657], + [967, 1025], + [9176, 9236], + [31271, 31292], + [5484, 5511], + [5122, 5159], + [1280, 1329], + [30883, 30901], + [30532, 30542], + [8202, 8227], + [21300, 21333], + [32066, 32114], + [11062, 11153], + [33006, 33043], + [24669, 24777], + [8082, 8149], + [27415, 27471], + [24098, 24189], + [23155, 23257], + [27019, 27126], + [6007, 6018], + [28811, 28917], + [4431, 4492], + [19729, 19815], + [16326, 16367], + [18592, 18682], + [16466, 16575], + [32400, 32499], + [1109, 1189], + [163, 242], + [30273, 30385], + [22694, 22737], + [9701, 9774], + [9410, 9455], + [15177, 15193], + [14074, 14156], + [23316, 23399], + [10939, 10983], + [23774, 23855], + [18728, 18836], + [16967, 17075], + [11256, 11357], + [16580, 16584], + [14766, 14829], + [24622, 24726], + [15456, 15521], + [5675, 5710], + [19496, 19606], + [28766, 28767], + [7344, 7412], + [2556, 2563], + [27267, 27349], + [13397, 13450], + [31124, 31145], + [21373, 21480], + [18192, 18237], + [7734, 7774], + [31010, 31115], + [30500, 30511], + [14876, 14877], + [27441, 27509], + [32671, 32693], + [10576, 10657], + [27960, 28070], + [22233, 22249], + [8592, 8701], + [18084, 18188], + [28076, 28162], + [22125, 22177], + [6599, 6700], + [31924, 31937], + [4564, 4674], + [15445, 15479], + [12098, 12198], + [6996, 7097], + [14720, 14819], + [25840, 25940], + [3325, 3388], + [11431, 11474], + [25746, 25814], + [10781, 10844], + [9860, 9872], + [856, 877], + [15574, 15659], + [2010, 2075], + [33072, 33122], + [31878, 31882], + [29982, 30078], + [11921, 11954], + [26590, 26631], + [290, 396], + [8495, 8582], + [2172, 2230], + [10275, 10372], + [20688, 20735], + [31161, 31217], + [32674, 32716], + [10643, 10677], + [4865, 4973], + [14237, 14318], + [18938, 18984], + [34649, 34722], + [17167, 17267], + [29915, 29921], + [22967, 22984], + [13061, 13123], + [26630, 26671], + [457, 531], + [10193, 10221], + [7245, 7249], + [13869, 13969], + [9071, 9117], + [21480, 21507], + [27993, 28055], + [33244, 33244], + [27256, 27329], + [34481, 34562], + [14557, 14592], + [27858, 27964], + [10319, 10418], + [7634, 7638], + [12861, 12942], + [30558, 30648], + [26123, 26174], + [27535, 27623], + [34347, 34374], + [31847, 31935], + [20253, 20351], + [29172, 29260], + [15069, 15110], + [26040, 26044], + [22506, 22571], + [11831, 11890], + [17997, 18040], + [17640, 17735], + [14877, 14980], + [23477, 23494], + [34359, 34378], + [20086, 20109], + [33138, 33155], + [10651, 10703], + [24402, 24461], + [17743, 17823], + [6798, 6860], + [18346, 18398], + [32846, 32931], + [25306, 25320], + [4060, 4144], + [20417, 20427], + [2915, 3005], + [4271, 4302], + [34707, 34717], + [26340, 26414], + [33061, 33075], + [1335, 1386], + [6684, 6754], + [19197, 19218], + [19918, 20004], + [22117, 22157], + [33642, 33754], + [31505, 31583], + [25835, 25889], + [17333, 17376], + [32734, 32782], + [29272, 29347], + [20859, 20880], + [5260, 5318], + [31335, 31411], + [13260, 13269], + [30105, 30185], + [23400, 23447], + [7940, 7961], + [3064, 3167], + [14071, 14090], + [14873, 14899], + [1432, 1499], + [13009, 13081], + [17882, 17988], + [32529, 32531], + [2249, 2266], + [28386, 28468], + [9076, 9137], + [29457, 29524], + [639, 656], + [10142, 10198], + [8853, 8923], + [29748, 29843], + [7508, 7582], + [34222, 34317], + [29001, 29042], + [21638, 21696], + [4031, 4131], + [31334, 31334], + [7188, 7262], + [7956, 8024], + [16368, 16459], + [16202, 16216], + [26706, 26733], + [22027, 22096], + [11954, 12036], + [6101, 6129], + [12691, 12736], + [2056, 2074], + [26363, 26414], + [18362, 18434], + [5840, 5892], + [24460, 24560], + [26987, 27018], + [9195, 9289], + [26529, 26556], + [25185, 25281], + [15571, 15668], + [6462, 6487], + [23547, 23554], + [27225, 27243], + [2852, 2854], + [15695, 15756], + [8464, 8535], + [3392, 3434], + [1310, 1338], + [16282, 16283], + [16164, 16252], + [22751, 22847], + [20645, 20754], + [33141, 33146], + [31754, 31863], + [3143, 3246], + [25156, 25161], + [24235, 24323], + [33011, 33061], + [18345, 18346], + [23482, 23511], + [11537, 11538], + [1731, 1777], + [15110, 15171], + [2636, 2678], + [30687, 30791], + [27425, 27504], + [13612, 13702], + [32529, 32565], + [15574, 15634], + [14103, 14165], + [21646, 21731], + [9155, 9215], + [16524, 16539], + [5882, 5934], + [12861, 12896], + [25297, 25344], + [6680, 6685], + [5308, 5376], + [9623, 9624], + [5281, 5296], + [7778, 7826], + [4570, 4647], + [6154, 6162], + [13291, 13377], + [24863, 24944], + [24411, 24456], + [5467, 5498], + [34165, 34226], + [21796, 21828], + [12379, 12487], + [24397, 24471], + [23440, 23502], + [19050, 19124], + [5790, 5854], + [29299, 29338], + [33816, 33901], + [4138, 4187], + [19125, 19165], + [9994, 10080], + [27622, 27714], + [29698, 29752], + [16833, 16880], + [13, 55], + [12292, 12367], + [18667, 18741], + [6328, 6399], + [19110, 19130], + [34073, 34184], + [33185, 33291], + [2746, 2856], + [26441, 26469], + [471, 535], + [29627, 29737], + [396, 456], + [791, 856], + [9643, 9687], + [19206, 19271], + [15067, 15147], + [4729, 4743], + [11996, 12041], + [15176, 15227], + [32384, 32413], + [10282, 10307], + [33014, 33071], + [1421, 1436], + [29743, 29751], + [4213, 4296], + [255, 261], + [16004, 16106], + [14567, 14637], + [7858, 7954], + [651, 656], + [9482, 9520], + [23610, 23715], + [6733, 6821], + [25395, 25475], + [26811, 26907], + [15745, 15832], + [2845, 2953], + [10975, 11051], + [4411, 4432], + [6847, 6876], + [29441, 29469], + [12546, 12569], + [19604, 19665], + [5566, 5597], + [28250, 28326], + [24449, 24461], + [21913, 21940], + [30532, 30536], + [5886, 5948], + [651, 746], + [14960, 15057], + [22973, 23055], + [15263, 15296], + [33710, 33752], + [22667, 22694], + [27322, 27374], + [2378, 2455], + [2914, 2918], + ], + 32323, + ), +] + + +class CountDaysWithoutMeetingsTestCase(unittest.TestCase): + @parameterized.expand(TEST_CASES) + def test_count_days_without_meetings( + self, days: int, meetings: List[List[int]], expected: int + ): + actual = count_days(days, meetings) + self.assertEqual(expected, actual) + + @parameterized.expand(TEST_CASES) + def test_count_days_without_meetings_2( + self, days: int, meetings: List[List[int]], expected: int + ): + actual = count_days_2(days, meetings) + self.assertEqual(expected, actual) + + +if __name__ == "__main__": + unittest.main() diff --git a/algorithms/intervals/merge_intervals/__init__.py b/algorithms/intervals/merge_intervals/__init__.py index 1bfa7bdc..9e4bab73 100644 --- a/algorithms/intervals/merge_intervals/__init__.py +++ b/algorithms/intervals/merge_intervals/__init__.py @@ -22,12 +22,18 @@ def merge(intervals: List[List[int]]) -> List[List[int]]: merged = [] for interval in closed_intervals: + current_interval_start_time = interval[0] + current_interval_end_time = interval[1] + last_merged_interval_end_time = merged[-1][1] if merged else float("-inf") + # if the merged array is empty or the last interval in the merged array does not overlap with the current interval - if not merged or merged[-1][1] < interval[0]: + if not merged or last_merged_interval_end_time < current_interval_start_time: # add it to the merged list merged.append(interval) else: # else we merge the intervals, by updating the max end time of the last interval in the merged list - merged[-1][1] = max(merged[-1][1], interval[1]) + merged[-1][1] = max( + last_merged_interval_end_time, current_interval_end_time + ) return merged