Skip to content

Commit e05d1ff

Browse files
Samuel FlenderSamuel Flender
Samuel Flender
authored and
Samuel Flender
committed
update all lessons
1 parent eeb7b3f commit e05d1ff

13 files changed

+965
-13
lines changed
File renamed without changes.

Lesson 2 - Binary Trees.ipynb renamed to Lesson 02 - Binary Trees.ipynb

Lines changed: 131 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
},
2121
{
2222
"cell_type": "code",
23-
"execution_count": 14,
23+
"execution_count": 1,
2424
"metadata": {},
2525
"outputs": [],
2626
"source": [
@@ -51,19 +51,16 @@
5151
" if not node:\n",
5252
" return []\n",
5353
" return dfs_inorder(node.l) + [node.v] + dfs_inorder(node.r)\n",
54-
" return vals\n",
5554
"\n",
5655
"def dfs_preorder(node):\n",
5756
" if not node:\n",
5857
" return []\n",
5958
" return [node.v] + dfs_inorder(node.l) + dfs_inorder(node.r)\n",
60-
" return vals\n",
6159
"\n",
6260
"def dfs_postorder(node):\n",
6361
" if not node:\n",
6462
" return []\n",
6563
" return dfs_inorder(node.l) + dfs_inorder(node.r) + [node.v]\n",
66-
" return vals\n",
6764
"\n",
6865
"def dfs_iterative(node):\n",
6966
" # surprise! we can also implement DFS iteratively, by replacing the Q with a stack:\n",
@@ -81,7 +78,7 @@
8178
},
8279
{
8380
"cell_type": "code",
84-
"execution_count": 15,
81+
"execution_count": 2,
8582
"metadata": {},
8683
"outputs": [],
8784
"source": [
@@ -101,7 +98,7 @@
10198
},
10299
{
103100
"cell_type": "code",
104-
"execution_count": 16,
101+
"execution_count": 3,
105102
"metadata": {},
106103
"outputs": [
107104
{
@@ -176,12 +173,138 @@
176173
"dfs_inorder(M)"
177174
]
178175
},
176+
{
177+
"cell_type": "markdown",
178+
"metadata": {},
179+
"source": [
180+
"## Is same-tree and is sub-tree problems"
181+
]
182+
},
179183
{
180184
"cell_type": "code",
181-
"execution_count": null,
185+
"execution_count": 2,
182186
"metadata": {},
183187
"outputs": [],
184-
"source": []
188+
"source": [
189+
"def same(n,m):\n",
190+
" '''\n",
191+
" returns True if n and m are the same tree\n",
192+
" '''\n",
193+
" \n",
194+
" if not n and not m: \n",
195+
" return True\n",
196+
" if (n and not m) or (m and not n): \n",
197+
" return False\n",
198+
" if n.val!=m.val:\n",
199+
" return False\n",
200+
" return same(n.l,m.l) and same(n.r,m.r)"
201+
]
202+
},
203+
{
204+
"cell_type": "code",
205+
"execution_count": 3,
206+
"metadata": {},
207+
"outputs": [],
208+
"source": [
209+
"def sub(n,m):\n",
210+
" '''\n",
211+
" returns True if m is a subtree of n\n",
212+
" '''\n",
213+
" \n",
214+
" if same(n,m): return True\n",
215+
" if not m: return True\n",
216+
" if not n: return False\n",
217+
" return sub(n.l,m) or sub(n.r,m) "
218+
]
219+
},
220+
{
221+
"cell_type": "markdown",
222+
"metadata": {},
223+
"source": [
224+
"## Problem: find lowest common ancesctor in BST"
225+
]
226+
},
227+
{
228+
"cell_type": "code",
229+
"execution_count": 15,
230+
"metadata": {},
231+
"outputs": [],
232+
"source": [
233+
"def lca(root,n,m):\n",
234+
" if n.v>root.v and m.v>root.v:\n",
235+
" # both are bigger, go to the right\n",
236+
" return lca(root.r,n,m)\n",
237+
"\n",
238+
" elif n.v<root.v and m.v<root.v:\n",
239+
" # both are smaller, go to the left\n",
240+
" return lca(root.l,n,m)\n",
241+
"\n",
242+
" else:\n",
243+
" # one is bigger, one is smaller - bingo!\n",
244+
" return root.v"
245+
]
246+
},
247+
{
248+
"cell_type": "code",
249+
"execution_count": 17,
250+
"metadata": {},
251+
"outputs": [],
252+
"source": [
253+
"# Consider this BST:\n",
254+
"# 5\n",
255+
"# 3 7\n",
256+
"# 2 4 6 8\n",
257+
"#\n",
258+
"# traversing this \"in order\" --> 2 3 4 5 6 7 8\n",
259+
"\n",
260+
"M = Node(5)\n",
261+
"M.l = Node(3)\n",
262+
"M.r = Node(7)\n",
263+
"M.l.l = Node(2)\n",
264+
"M.l.r = Node(4)\n",
265+
"M.r.l = Node(6)\n",
266+
"M.r.r = Node(8)"
267+
]
268+
},
269+
{
270+
"cell_type": "code",
271+
"execution_count": 18,
272+
"metadata": {},
273+
"outputs": [
274+
{
275+
"data": {
276+
"text/plain": [
277+
"3"
278+
]
279+
},
280+
"execution_count": 18,
281+
"metadata": {},
282+
"output_type": "execute_result"
283+
}
284+
],
285+
"source": [
286+
"lca(M,Node(2),Node(4))"
287+
]
288+
},
289+
{
290+
"cell_type": "code",
291+
"execution_count": 19,
292+
"metadata": {},
293+
"outputs": [
294+
{
295+
"data": {
296+
"text/plain": [
297+
"7"
298+
]
299+
},
300+
"execution_count": 19,
301+
"metadata": {},
302+
"output_type": "execute_result"
303+
}
304+
],
305+
"source": [
306+
"lca(M,Node(6),Node(8))"
307+
]
185308
},
186309
{
187310
"cell_type": "code",
File renamed without changes.

Lesson 4 - Dynamic Programming.ipynb renamed to Lesson 04 - Dynamic Programming.ipynb

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,46 @@
251251
"coin_change(13, [1,3,7])"
252252
]
253253
},
254+
{
255+
"cell_type": "code",
256+
"execution_count": 5,
257+
"metadata": {},
258+
"outputs": [],
259+
"source": [
260+
"from functools import lru_cache\n",
261+
"def coin_change_memo(coins,target):\n",
262+
"\t\n",
263+
"\t@lru_cache\n",
264+
"\tdef _coinchange(x):\n",
265+
"\t\tif x==0:\n",
266+
"\t\t\treturn 0\n",
267+
"\t\telse:\n",
268+
"\t\t\tcandidates = [1+_coinchange(x-c) for c in coins if x-c>=0]\n",
269+
"\t\t\treturn min(candidates if candidates else -1)\n",
270+
"\n",
271+
"\treturn _coinchange(target)"
272+
]
273+
},
274+
{
275+
"cell_type": "code",
276+
"execution_count": 6,
277+
"metadata": {},
278+
"outputs": [
279+
{
280+
"data": {
281+
"text/plain": [
282+
"3"
283+
]
284+
},
285+
"execution_count": 6,
286+
"metadata": {},
287+
"output_type": "execute_result"
288+
}
289+
],
290+
"source": [
291+
"coin_change_memo([1,3,7],13)"
292+
]
293+
},
254294
{
255295
"cell_type": "markdown",
256296
"metadata": {},

Lesson 5 - Graphs.ipynb renamed to Lesson 05 - Graphs.ipynb

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"cells": [
33
{
44
"cell_type": "code",
5-
"execution_count": 24,
5+
"execution_count": 3,
66
"id": "1c8dea41-b247-40c9-9e44-7012ced2db06",
77
"metadata": {},
88
"outputs": [],
@@ -325,6 +325,66 @@
325325
"count_num_ccs([[0,1],[1,2],[3,4]], 5)"
326326
]
327327
},
328+
{
329+
"cell_type": "code",
330+
"execution_count": 7,
331+
"id": "cc0fb250-c012-4b15-be21-298d53bfedf2",
332+
"metadata": {},
333+
"outputs": [],
334+
"source": [
335+
"def count_num_ccs_bfs(edges, N):\n",
336+
" '''\n",
337+
" same as above but using bfs instead of dfs\n",
338+
" '''\n",
339+
" \n",
340+
" graph = [[] for _ in range(N)]\n",
341+
" for a,b in edges:\n",
342+
" graph[a].append(b)\n",
343+
" graph[b].append(a)\n",
344+
" \n",
345+
" seen = [False for _ in range(N)]\n",
346+
" \n",
347+
" def bfs(node):\n",
348+
" Q = deque([node])\n",
349+
" while Q:\n",
350+
" node = Q.popleft()\n",
351+
" seen[node]=True\n",
352+
" for neighbor in graph[node]:\n",
353+
" if not seen[neighbor]:\n",
354+
" #seen[neighbor]=True\n",
355+
" Q.append(neighbor)\n",
356+
" \n",
357+
" counter=0\n",
358+
" for i in range(N):\n",
359+
" if not seen[i]:\n",
360+
" counter+=1\n",
361+
" #seen[i]=True\n",
362+
" bfs(i)\n",
363+
" \n",
364+
" return counter"
365+
]
366+
},
367+
{
368+
"cell_type": "code",
369+
"execution_count": 8,
370+
"id": "299c6c1f-d402-41d6-8e5e-e44a055a3080",
371+
"metadata": {},
372+
"outputs": [
373+
{
374+
"data": {
375+
"text/plain": [
376+
"2"
377+
]
378+
},
379+
"execution_count": 8,
380+
"metadata": {},
381+
"output_type": "execute_result"
382+
}
383+
],
384+
"source": [
385+
"count_num_ccs_bfs([[0,1],[1,2],[3,4]], 5)"
386+
]
387+
},
328388
{
329389
"cell_type": "markdown",
330390
"id": "44399bd3-384e-4580-aeeb-055f98086cc6",

Lesson 6 - Heaps.ipynb renamed to Lesson 06 - Heaps.ipynb

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,75 @@
246246
"num_rooms( [[0,30],[5,10],[15,20]] )"
247247
]
248248
},
249+
{
250+
"cell_type": "markdown",
251+
"id": "771dd889-30ae-4e77-8b97-7af7bf33f90c",
252+
"metadata": {},
253+
"source": [
254+
"# Problem: get the k closest points to origin\n",
255+
"\n",
256+
"This is another problem of the type \"get the k smallest\" or \"get the k largest\". In these cases, a heap is always prefered. Why? It's a waste to sort the entire array!\n",
257+
"\n",
258+
"Let's say, the array has length 1M, and we want the top 5 smallest elements. Using the heap (instead of sorting) would be log(1M)/log(5) ~ 9X faster!"
259+
]
260+
},
261+
{
262+
"cell_type": "code",
263+
"execution_count": 3,
264+
"id": "aed6d460-4b9e-4376-9aa9-d8bfbd7620be",
265+
"metadata": {},
266+
"outputs": [
267+
{
268+
"data": {
269+
"text/plain": [
270+
"8.58405934844036"
271+
]
272+
},
273+
"execution_count": 3,
274+
"metadata": {},
275+
"output_type": "execute_result"
276+
}
277+
],
278+
"source": [
279+
"import numpy as np\n",
280+
"np.log(1e6)/np.log(5)"
281+
]
282+
},
283+
{
284+
"cell_type": "code",
285+
"execution_count": 4,
286+
"id": "b4c43aa3-4062-47c4-bb44-ec018b3607bf",
287+
"metadata": {},
288+
"outputs": [],
289+
"source": [
290+
"def kClosest(self,points,k):\n",
291+
" '''\n",
292+
" min-heap solution, O(Nlogk)\n",
293+
" Note we use negative squared distance here because python heapq only supports max-heap.\n",
294+
" '''\n",
295+
"\n",
296+
" def calc_dist(p):\n",
297+
" # return the negative squared distance\n",
298+
" return -(p[0]**2+p[1]**2)\n",
299+
"\n",
300+
" heap = []\n",
301+
" for i in range(k):\n",
302+
" dist = calc_dist(points[i])\n",
303+
" heapq.heappush(heap,(dist,i)) # <O(log(k))\n",
304+
"\n",
305+
" for i in range(k,len(points)):\n",
306+
" dist = calc_dist(points[i])\n",
307+
" if dist>heap[0][0]:\n",
308+
" heapq.heappop(heap)\n",
309+
" heapq.heappush(heap,(dist,i)) # O(log(k))\n",
310+
"\n",
311+
" return [points[heap[i][1]] for i in range(k)]"
312+
]
313+
},
249314
{
250315
"cell_type": "code",
251316
"execution_count": null,
252-
"id": "5f91ef16-8a5d-4db2-9065-75a3c7e1d143",
317+
"id": "45e36328-536c-4017-a2b7-fb6b70cc7cb3",
253318
"metadata": {},
254319
"outputs": [],
255320
"source": []
File renamed without changes.

0 commit comments

Comments
 (0)