Skip to content

Commit 6fed9e7

Browse files
committed
update to change tracking
1 parent 55189b3 commit 6fed9e7

File tree

1 file changed

+95
-11
lines changed

1 file changed

+95
-11
lines changed

implementations/Technique - Interval Sweep .ipynb renamed to implementations/Technique - Change Tracking.ipynb

Lines changed: 95 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"cell_type": "markdown",
55
"metadata": {},
66
"source": [
7-
"## Technique - Interval Sweep\n",
7+
"## Technique - Change Tracking\n",
88
"\n",
99
"This is a cool trick I learned from [@lee215](https://leetcode.com/problems/maximum-sum-obtained-of-any-permutation/discuss/854206/JavaC++Python-Sweep-Line) on LeetCode for efficiently handling some types of overlapping interval problems. \n",
1010
"\n",
@@ -70,11 +70,11 @@
7070
"cell_type": "markdown",
7171
"metadata": {},
7272
"source": [
73-
"## Interval sweep technique\n",
73+
"## Tracking changes technique\n",
7474
"\n",
75-
"Consider that each time we see a range, all values between the start and the end have are now present in one range (plus any others). We can only get around the quadratic complexity by skipping these middle values. Let's keep a Counter `bounds_counts`; for each range given, `bounds_count[range[0]] += 1` and `bounds_count[range[0]+1] -= 1` (this may sound weird, but hang on). \n",
75+
"Consider that each time we see a range, all values between the start and the end have are now present in one range (plus any others). We can only get around the quadratic complexity by skipping these middle values. So instead, what if we keep track of the boundaries of each range, and then just track the number of times an interval begins or ends on a particular boundary? Then we can go linearly through the bounds and just look at the changes in the number of covering intervals at each index.\n",
7676
"\n",
77-
"If our ranges are `[[1,3],[2,4]]`, then the correct result would be `{1:1, 2:2, 3:2, 4:1}`. Using this strategy, `bounds_counts` looks like the following:\n",
77+
"Let's keep a Counter `bounds_counts`; for each range given, `bounds_count[range[0]] += 1` and `bounds_count[range[0]+1] -= 1` (this may sound weird, but hang on). If our ranges are `[[1,3],[2,4]]`, then the correct result would be `{1:1, 2:2, 3:2, 4:1}`. Using this strategy, `bounds_counts` looks like the following:\n",
7878
"```\n",
7979
"[1,3] -> {1:1, 4:-1}\n",
8080
"[2,4] -> {1:1, 2:1, 4: -1, 5:-1}\n",
@@ -89,7 +89,7 @@
8989
"4 1 (-1) {1:1, 2:2, 3:2, 4:1}\n",
9090
"5 0 (-1) same as above; don't include values with frequency 0. \n",
9191
"```\n",
92-
"so frequencies now corretly reflects the count of intervals covering each value, and calculates it in linear time. In code:"
92+
"so frequencies now correctly reflects the count of intervals covering each value, and calculates it in linear time. In code:"
9393
]
9494
},
9595
{
@@ -142,14 +142,14 @@
142142
},
143143
{
144144
"cell_type": "code",
145-
"execution_count": 50,
145+
"execution_count": 54,
146146
"metadata": {},
147147
"outputs": [],
148148
"source": [
149149
"from collections import Counter\n",
150150
"from typing import List\n",
151151
"\n",
152-
"def interval_sweep(requests):\n",
152+
"def interval_sweep_shitty(requests):\n",
153153
" \"\"\"\n",
154154
" Given a list of ranges, return an array\n",
155155
" where arr[i] equals the number of ranges\n",
@@ -171,12 +171,26 @@
171171
" return overlap_count\n",
172172
"\n",
173173
"\n",
174+
"def interval_sweep(nums_len, requests):\n",
175+
" \"\"\"\n",
176+
" Same as above, but borrowing from @lee215's\n",
177+
" technique which is faster.\n",
178+
" \"\"\"\n",
179+
" counts = [0] * (nums_len+1)\n",
180+
" for start,end in requests:\n",
181+
" counts[start] += 1\n",
182+
" counts[end+1] -= 1\n",
183+
"\n",
184+
" for i in range(1, nums_len+1):\n",
185+
" counts[i] += counts[i-1]\n",
186+
" return counts\n",
187+
"\n",
174188
"class Solution:\n",
175189
" def maxSumRangeQuery(self, nums: List[int], requests: List[List[int]]) -> int:\n",
176190
" nums.sort(reverse=True)\n",
177-
" overlap_count = interval_sweep(requests) \n",
191+
" overlap_count = interval_sweep(len(nums), requests) \n",
178192
" max_sum = 0\n",
179-
" for i, frequency in enumerate(sorted(overlap_count, reverse=True)):\n",
193+
" for i, frequency in enumerate(sorted(overlap_count[:-1], reverse=True)):\n",
180194
" max_sum += frequency*nums[i]\n",
181195
" return max_sum % (10**9 + 7)\n",
182196
" \n",
@@ -191,12 +205,82 @@
191205
" assert actual == expected, f\"{nums, requests}: {expected} != {actual}\""
192206
]
193207
},
208+
{
209+
"cell_type": "markdown",
210+
"metadata": {},
211+
"source": [
212+
"## [Corporate Flight Bookings](https://leetcode.com/problems/corporate-flight-bookings/)"
213+
]
214+
},
215+
{
216+
"cell_type": "code",
217+
"execution_count": 60,
218+
"metadata": {},
219+
"outputs": [],
220+
"source": [
221+
"class Solution:\n",
222+
" def corpFlightBookings(self, bookings: List[List[int]], n: int) -> List[int]:\n",
223+
" flights = [0] * (n+1)\n",
224+
" for first,last,count in bookings:\n",
225+
" flights[first-1] += count\n",
226+
" flights[last] -= count \n",
227+
" for i in range(1, n):\n",
228+
" flights[i] += flights[i-1]\n",
229+
" return flights[:-1]\n",
230+
"\n",
231+
"s = Solution()\n",
232+
"cases = [\n",
233+
" ([[1,2,10],[2,3,20],[2,5,25]], 5, [10,55,45,25,25])\n",
234+
"]\n",
235+
"for bookings, n, expected in cases:\n",
236+
" actual = s.corpFlightBookings(bookings, n)\n",
237+
" assert actual == expected, f\"{bookings, n}: {expected} != {actual}\""
238+
]
239+
},
240+
{
241+
"cell_type": "markdown",
242+
"metadata": {},
243+
"source": [
244+
"## [Car Pooling](https://leetcode.com/problems/car-pooling/)"
245+
]
246+
},
194247
{
195248
"cell_type": "code",
196-
"execution_count": null,
249+
"execution_count": 70,
197250
"metadata": {},
198251
"outputs": [],
199-
"source": []
252+
"source": [
253+
"from collections import Counter\n",
254+
"\n",
255+
"class Solution:\n",
256+
" def carPooling(self, trips: List[List[int]], capacity: int) -> bool:\n",
257+
" first, last = float('inf'), -float('inf')\n",
258+
" stops = Counter()\n",
259+
" for passengers, start, end in trips: \n",
260+
" stops[start] += passengers\n",
261+
" stops[end] -= passengers\n",
262+
" first = min(first, start)\n",
263+
" last = max(last, end)\n",
264+
"\n",
265+
" seats = 0\n",
266+
" for i in range(first, last+1):\n",
267+
" seats += stops[i]\n",
268+
" if seats > capacity:\n",
269+
" return False\n",
270+
" return True\n",
271+
"\n",
272+
"s = Solution()\n",
273+
"cases = [\n",
274+
" ([[2,1,5],[3,3,7]], 4, False),\n",
275+
" ([[2,1,5],[3,3,7]], 5, True),\n",
276+
" ([[2,1,5],[3,5,7]], 3, True),\n",
277+
" ([[3,2,7],[3,7,9],[8,3,9]], 11, True),\n",
278+
"]\n",
279+
" \n",
280+
"for trips, capacity, expected in cases:\n",
281+
" actual = s.carPooling(trips, capacity)\n",
282+
" assert actual == expected, f\"{trips, capacity}: {expected} != {actual}\""
283+
]
200284
}
201285
],
202286
"metadata": {

0 commit comments

Comments
 (0)