Add coding exercises for Facebook interviews
Add attempts at solving coding problems to Briefcase.
This commit is contained in:
		
							parent
							
								
									d2d772e43e
								
							
						
					
					
						commit
						aa66d9b83d
					
				
					 66 changed files with 2994 additions and 0 deletions
				
			
		
							
								
								
									
										71
									
								
								scratch/facebook/anglocize-int.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								scratch/facebook/anglocize-int.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | |||
| THOUSAND = int(1e3) | ||||
| MILLION = int(1e6) | ||||
| BILLION = int(1e9) | ||||
| TRILLION = int(1e12) | ||||
| 
 | ||||
| facts = { | ||||
|     1: "One", | ||||
|     2: "Two", | ||||
|     3: "Three", | ||||
|     4: "Four", | ||||
|     5: "Five", | ||||
|     6: "Six", | ||||
|     7: "Seven", | ||||
|     8: "Eight", | ||||
|     9: "Nine", | ||||
|     10: "Ten", | ||||
|     11: "Eleven", | ||||
|     12: "Twelve", | ||||
|     13: "Thirteen", | ||||
|     14: "Fourteen", | ||||
|     15: "Fifteen", | ||||
|     16: "Sixteen", | ||||
|     17: "Seventeen", | ||||
|     18: "Eighteen", | ||||
|     19: "Nineteen", | ||||
|     20: "Twenty", | ||||
|     30: "Thirty", | ||||
|     40: "Forty", | ||||
|     50: "Fifty", | ||||
|     60: "Sixty", | ||||
|     70: "Seventy", | ||||
|     80: "Eighty", | ||||
|     90: "Ninety", | ||||
|     100: "Hundred", | ||||
|     THOUSAND: "Thousand", | ||||
|     MILLION: "Million", | ||||
|     BILLION: "Billion", | ||||
|     TRILLION: "Trillion", | ||||
| } | ||||
| 
 | ||||
| def anglocize(x): | ||||
|     # ones | ||||
|     if x >= 0 and x < 10: | ||||
|         pass | ||||
| 
 | ||||
|     # tens | ||||
|     elif x < 100: | ||||
|         pass | ||||
| 
 | ||||
|     # hundreds | ||||
|     elif x < THOUSAND: | ||||
|         pass | ||||
| 
 | ||||
|     # thousands | ||||
|     elif x < MILLION: | ||||
|         pass | ||||
| 
 | ||||
|     # millions | ||||
|     elif x < BILLION: | ||||
|         pass | ||||
| 
 | ||||
|     # billion | ||||
|     elif x < TRILLION: | ||||
|         pass | ||||
| 
 | ||||
|     # trillion | ||||
|     else: | ||||
|         pass | ||||
| 
 | ||||
| x = 1234 | ||||
| assert anglocize(x) == "One Thousand, Two Hundred Thirty Four" | ||||
							
								
								
									
										70
									
								
								scratch/facebook/balanced-binary-tree.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								scratch/facebook/balanced-binary-tree.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| from collections import deque | ||||
| 
 | ||||
| class Node(object): | ||||
|     # __init__ :: T(A) | ||||
|     def __init__(self, value=None, left=None, right=None): | ||||
|         self.value = value | ||||
|         self.left = left | ||||
|         self.right = right | ||||
| 
 | ||||
|     # insert_left :: T(A) -> A -> T(A) | ||||
|     def insert_left(self, value): | ||||
|         self.left = Node(value) | ||||
|         return self.left | ||||
| 
 | ||||
|     # insert_right :: T(A) -> A -> T(A) | ||||
|     def insert_right(self, value): | ||||
|         self.right = Node(value) | ||||
|         return self.right | ||||
| 
 | ||||
|     # is_superbalanced :: T(A) -> Bool | ||||
|     def is_superbalanced(self): | ||||
|         xs = deque() | ||||
|         min_depth, max_depth = float('inf'), float('-inf') | ||||
|         xs.append((self, 0)) | ||||
|         while xs: | ||||
|             x, d = xs.popleft() | ||||
|             # Only redefine the depths at leaf nodes | ||||
|             if not x.left and not x.right: | ||||
|                 min_depth, max_depth = min(min_depth, d), max(max_depth, d) | ||||
|             if x.left: | ||||
|                 xs.append((x.left, d + 1)) | ||||
|             if x.right: | ||||
|                 xs.append((x.right, d + 1)) | ||||
|         return max_depth - min_depth <= 1 | ||||
| 
 | ||||
|     # __repr__ :: T(A) -> String | ||||
|     def __repr__(self): | ||||
|         result = '' | ||||
|         xs = deque() | ||||
|         xs.append((self, 0)) | ||||
|         while xs: | ||||
|             node, indent = xs.popleft() | ||||
|             result += '{i}{x}\n'.format(i=' ' * indent, x=node.value) | ||||
|             if node.left: | ||||
|                 xs.append((node.left, indent + 2)) | ||||
|             if node.right: | ||||
|                 xs.append((node.right, indent + 2)) | ||||
|         return result | ||||
| 
 | ||||
| # from_array :: List(A) -> T(A) | ||||
| def from_array(values): | ||||
|     xs = deque() | ||||
|     root = Node() | ||||
|     xs.append(root) | ||||
|     for value in values: | ||||
|         node = xs.popleft() | ||||
|         node.value = value | ||||
|         node.left = Node() | ||||
|         xs.append(node.left) | ||||
|         node.right = Node() | ||||
|         xs.append(node.right) | ||||
|     return root | ||||
| 
 | ||||
| x = from_array([1, 1, 1, 1, 1, 1, 1]) | ||||
| print(x) | ||||
| print(x.is_superbalanced()) | ||||
| 
 | ||||
| x = Node(1, Node(2), Node(3)) | ||||
| print(x) | ||||
| print(x.is_superbalanced()) | ||||
							
								
								
									
										112
									
								
								scratch/facebook/breakfast-generator.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								scratch/facebook/breakfast-generator.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,112 @@ | |||
| # After being inspired by... | ||||
| # craftinginterpreters.com/representing-code.html | ||||
| # ...I'm implementing the breakfast generator that the author describes | ||||
| # therein. | ||||
| 
 | ||||
| import random | ||||
| import string | ||||
| 
 | ||||
| # Breakfast | ||||
| 
 | ||||
| def breakfast(): | ||||
|     fn = random.choice([ | ||||
|         lambda: " ".join([protein(), "with", breakfast(), "on the side"]), | ||||
|         lambda: protein(), | ||||
|         lambda: bread(), | ||||
|     ]) | ||||
|     return fn() | ||||
| 
 | ||||
| def protein(): | ||||
|     fn = random.choice([ | ||||
|         lambda: " ".join([qualifier(), "crispy", "bacon"]), | ||||
|         lambda: "sausage", | ||||
|         lambda: " ".join([cooking_method(), "sausage"]), | ||||
|     ]) | ||||
|     return fn() | ||||
| 
 | ||||
| def qualifier(): | ||||
|     fn = random.choice([ | ||||
|         lambda: "really", | ||||
|         lambda: "super", | ||||
|         lambda: " ".join(["really", qualifier()]), | ||||
|     ]) | ||||
|     return fn() | ||||
| 
 | ||||
| def cooking_method(): | ||||
|     return random.choice([ | ||||
|         "scrambled", | ||||
|         "poached", | ||||
|         "fried", | ||||
|     ]) | ||||
| 
 | ||||
| def bread(): | ||||
|     return random.choice([ | ||||
|         "toast", | ||||
|         "biscuits", | ||||
|         "English muffin", | ||||
|     ]) | ||||
| 
 | ||||
| print(breakfast()) | ||||
| 
 | ||||
| # Expression Language | ||||
| 
 | ||||
| # Because Python is a strictly evaluated language any functions that are | ||||
| # mutually recursive won't terminate and will overflow our stack. Therefore, any | ||||
| # non-terminals expressed in an alternative are wrapped in lambdas as thunks. | ||||
| 
 | ||||
| def expression(): | ||||
|     fn = random.choice([ | ||||
|         lambda: literal(), | ||||
|         lambda: binary(), | ||||
|     ]) | ||||
|     return fn() | ||||
| 
 | ||||
| def literal(): | ||||
|     return str(random.randint(0, 100)) | ||||
| 
 | ||||
| def binary(): | ||||
|     return " ".join([expression(), operator(), expression()]) | ||||
| 
 | ||||
| def operator(): | ||||
|     return random.choice(["+", "*"]) | ||||
| 
 | ||||
| print(expression()) | ||||
| 
 | ||||
| # Lox | ||||
| 
 | ||||
| def lox_expression(): | ||||
|     fn = random.choice([ | ||||
|         lambda: lox_literal(), | ||||
|         lambda: lox_unary(), | ||||
|         lambda: lox_binary(), | ||||
|         lambda: lox_grouping(), | ||||
|     ]) | ||||
|     return fn() | ||||
| 
 | ||||
| def lox_literal(): | ||||
|     fn = random.choice([ | ||||
|         lambda: str(random.randint(0, 100)), | ||||
|         lambda: lox_string(), | ||||
|         lambda: random.choice(["true", "false"]), | ||||
|         lambda: "nil", | ||||
|     ]) | ||||
|     return fn() | ||||
| 
 | ||||
| def lox_string(): | ||||
|     return "\"{}\"".format( | ||||
|         "".join(random.choice(string.ascii_lowercase) | ||||
|                 for _ in range(random.randint(0, 25)))) | ||||
| 
 | ||||
| def lox_grouping(): | ||||
|     return "(" + lox_expression() + ")" | ||||
| 
 | ||||
| def lox_unary(): | ||||
|     return random.choice(["-", "!"]) + lox_expression() | ||||
| 
 | ||||
| def lox_binary(): | ||||
|     return lox_expression() + lox_operator() + lox_expression() | ||||
| 
 | ||||
| def lox_operator(): | ||||
|     return random.choice(["==", "!=", "<", "<=", ">", ">=", "+", "-", "*", "/"]) | ||||
| 
 | ||||
| print(lox_expression()) | ||||
							
								
								
									
										79
									
								
								scratch/facebook/bst-checker.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								scratch/facebook/bst-checker.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,79 @@ | |||
| from collections import deque | ||||
| 
 | ||||
| class Node(object): | ||||
|     def __init__(self, value, left=None, right=None): | ||||
|         self.value = value | ||||
|         self.left = left | ||||
|         self.right = right | ||||
| 
 | ||||
|     def insert_left(self, value): | ||||
|         self.left = Node(value) | ||||
|         return self.left | ||||
| 
 | ||||
|     def insert_right(self, value): | ||||
|         self.right = Node(value) | ||||
|         return self.right | ||||
| 
 | ||||
|     def min(self): | ||||
|         xs = deque() | ||||
|         result = float('inf') | ||||
|         xs.append(self) | ||||
|         while xs: | ||||
|             node = xs.popleft() | ||||
|             result = min(result, node.value) | ||||
|             if node.left: | ||||
|                 xs.append(node.left) | ||||
|             if node.right: | ||||
|                 xs.append(node.right) | ||||
|         return result | ||||
| 
 | ||||
|     def max(self): | ||||
|         xs = deque() | ||||
|         result = float('-inf') | ||||
|         xs.append(self) | ||||
|         while xs: | ||||
|             node = xs.popleft() | ||||
|             result = max(result, node.value) | ||||
|             if node.left: | ||||
|                 xs.append(node.left) | ||||
|             if node.right: | ||||
|                 xs.append(node.right) | ||||
|         return result | ||||
| 
 | ||||
|     def is_bst(self): | ||||
|         result = True | ||||
|         if self.left: | ||||
|             result = result and self.left.max() < self.value | ||||
|         if self.right: | ||||
|             result = result and self.right.min() > self.value | ||||
|         return result | ||||
| 
 | ||||
| 
 | ||||
| x = Node( | ||||
|     50, | ||||
|     Node( | ||||
|         17, | ||||
|         Node( | ||||
|             12, | ||||
|             Node(9), | ||||
|             Node(14), | ||||
|         ), | ||||
|         Node( | ||||
|             23, | ||||
|             Node(19), | ||||
|         ), | ||||
|     ), | ||||
|     Node( | ||||
|         72, | ||||
|         Node( | ||||
|             54, | ||||
|             None, | ||||
|             Node(67) | ||||
|         ), | ||||
|         Node(76), | ||||
|     ), | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| assert x.is_bst() | ||||
| print("Success!") | ||||
							
								
								
									
										19
									
								
								scratch/facebook/cafe-order-checker.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								scratch/facebook/cafe-order-checker.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | |||
| def orders_are_sorted(take_out, dine_in, audit): | ||||
|     if len(take_out) + len(dine_in) != len(audit): | ||||
|         return False | ||||
| 
 | ||||
|     i, j = 0, 0 | ||||
|     for x in audit: | ||||
|         if i < len(take_out) and take_out[i] == x: | ||||
|             i += 1 | ||||
|         elif j < len(dine_in) and dine_in[j] == x: | ||||
|             j += 1 | ||||
|         else: | ||||
|             return False | ||||
|     return True | ||||
| 
 | ||||
| 
 | ||||
| assert orders_are_sorted([1,3,5], [2,4,6], [1,2,4,3,6,5]) | ||||
| assert not orders_are_sorted([1,3,5], [2,4,6], [1,2,4,5,6,3]) | ||||
| assert orders_are_sorted([], [2,4,6], [2,4,6]) | ||||
| print("Success!") | ||||
							
								
								
									
										61
									
								
								scratch/facebook/cake_thief.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								scratch/facebook/cake_thief.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,61 @@ | |||
| from math import floor | ||||
| 
 | ||||
| def print_table(table): | ||||
|     print('\n-- TABLE --') | ||||
|     for row in range(len(table)): | ||||
|         x = '' | ||||
|         for col in range(len(table[row])): | ||||
|             x += ' ' + str(table[row][col]) | ||||
|         print(x) | ||||
| 
 | ||||
| def leftover(capacity, kg): | ||||
|     n = floor(capacity / kg) | ||||
|     return n, capacity - (n * kg) | ||||
| 
 | ||||
| def init_table(num_rows, num_cols): | ||||
|     table = [] | ||||
|     for _ in range(num_rows): | ||||
|         row = [] | ||||
|         for _ in range(num_cols): | ||||
|             row.append(0) | ||||
|         table.append(row) | ||||
|     return table | ||||
| 
 | ||||
| def get(table, row, col): | ||||
|     if row < 0 or col < 0: | ||||
|         return 0 | ||||
|     return table[row][col] | ||||
| 
 | ||||
| def max_haul(items, capacity): | ||||
|     table = init_table(len(items), capacity) | ||||
| 
 | ||||
|     for row in range(len(table)): | ||||
|         for col in range(len(table[row])): | ||||
|             curr_capacity = col + 1 | ||||
|             kg, val = items[row] | ||||
|             # A | ||||
|             a = get(table, row - 1, col) | ||||
|             # B | ||||
|             n, lo = leftover(curr_capacity, kg) | ||||
|             b = (val * n) + get(table, row - 1, lo - 1) | ||||
|             # commit | ||||
|             if kg > curr_capacity: | ||||
|                 table[row][col] = a | ||||
|             else: | ||||
|                 print(n, lo) | ||||
|                 table[row][col] = max([a, b]) | ||||
|             print_table(table) | ||||
|     return table[-1][-1] | ||||
| 
 | ||||
| # There are multiple variants of this problem: | ||||
| #   1. We're allowed to take multiple of each item. | ||||
| #   2. We can only take one of each item. | ||||
| #   3. We can only take a fixed amount of each item. | ||||
| 
 | ||||
| items = [(7,160), (3,90), (2,15)] | ||||
| capacity = 20 | ||||
| result = max_haul(items, capacity) | ||||
| expected = None | ||||
| print("Result: {} == Expected: {}".format(result, expected)) | ||||
| assert result == expected | ||||
| print("Success!") | ||||
							
								
								
									
										46
									
								
								scratch/facebook/camping-knapsack.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								scratch/facebook/camping-knapsack.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | |||
| from utils import get, init_table, print_table | ||||
| 
 | ||||
| def max_haul(capacity, items, names): | ||||
|     table = init_table(rows=len(items), cols=capacity, default=0) | ||||
|     items_table = init_table(rows=len(items), cols=capacity, default=[]) | ||||
|     for row in range(len(table)): | ||||
|         for col in range(len(table[row])): | ||||
|             kg, value = items[row] | ||||
|             curr_capacity = col + 1 | ||||
| 
 | ||||
|             if kg > curr_capacity: | ||||
|                 a = 0 | ||||
|             else: | ||||
|                 a = value + get(table, row - 1, curr_capacity - kg - 1) | ||||
|             b = get(table, row - 1, col) | ||||
| 
 | ||||
|             if a > b: | ||||
|                 rest = get(items_table, row - 1, curr_capacity - kg - 1) | ||||
|                 knapsack = [names.get(items[row])] | ||||
|                 if rest: | ||||
|                     knapsack += rest | ||||
|             else: | ||||
|                 knapsack = get(items_table, row - 1, col) | ||||
| 
 | ||||
|             table[row][col] = max([a, b]) | ||||
|             items_table[row][col] = knapsack | ||||
|         print_table(table) | ||||
|     return items_table[-1][-1] | ||||
| 
 | ||||
| water = (3, 10) | ||||
| book = (1, 3) | ||||
| food = (2, 9) | ||||
| jacket = (2, 5) | ||||
| camera = (1, 6) | ||||
| items = [water, book, food, jacket, camera] | ||||
| result = max_haul(6, items, { | ||||
|     water: 'water', | ||||
|     book: 'book', | ||||
|     food: 'food', | ||||
|     jacket: 'jacket', | ||||
|     camera: 'camera', | ||||
| }) | ||||
| expected = ['camera', 'food', 'water'] | ||||
| print(result, expected) | ||||
| assert result == expected | ||||
| print("Success!") | ||||
							
								
								
									
										50
									
								
								scratch/facebook/coin.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								scratch/facebook/coin.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| def init_table(rows=0, cols=0, default=None): | ||||
|     table = [] | ||||
|     for _ in range(rows): | ||||
|         row = [] | ||||
|         for _ in range(cols): | ||||
|             row.append(default) | ||||
|         table.append(row) | ||||
|     return table | ||||
| 
 | ||||
| def print_table(table): | ||||
|     result = '' | ||||
|     for row in range(len(table)): | ||||
|         x = '' | ||||
|         for col in range(len(table[row])): | ||||
|             x += str(table[row][col]) + ' ' | ||||
|         result += x + '\n' | ||||
|     print(result) | ||||
| 
 | ||||
| def get(table, row, col): | ||||
|     if row < 0 or col < 0: | ||||
|         return 0 | ||||
|     else: | ||||
|         return table[row][col] | ||||
| 
 | ||||
| def make_change(coins, amt): | ||||
|     table = init_table(rows=len(coins), cols=amt, default=0) | ||||
|     for row in range(len(table)): | ||||
|         for col in range(len(table[row])): | ||||
|             coin = coins[row] | ||||
|             curr_amt = col + 1 | ||||
|             pull_down = get(table, row - 1, col) | ||||
| 
 | ||||
|             if curr_amt < coin: | ||||
|                 table[row][col] = pull_down | ||||
|             elif curr_amt == coin: | ||||
|                 table[row][col] = pull_down + 1 | ||||
|             else: | ||||
|                 leftover = get(table, row, curr_amt - coin - 1) | ||||
|                 table[row][col] = pull_down + leftover | ||||
| 
 | ||||
|     print_table(table) | ||||
|     return table[-1][-1] | ||||
| 
 | ||||
| #   1 2 3 4 | ||||
| # 1 1 1 1 1 | ||||
| # 2 1 1 2 2 | ||||
| # 3 1 1 3 4 | ||||
| 
 | ||||
| result = make_change([3,2,1], 4) | ||||
| print(result) | ||||
							
								
								
									
										19
									
								
								scratch/facebook/delete-node.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								scratch/facebook/delete-node.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | |||
| from linked_list import Node, from_list | ||||
| 
 | ||||
| def delete(node): | ||||
|     if not node.next: | ||||
|         node.value = None | ||||
|     else: | ||||
|         node.value = node.next.value | ||||
|         node.next = node.next.next | ||||
| 
 | ||||
| one = Node(1) | ||||
| two = Node(2) | ||||
| three = Node(3) | ||||
| 
 | ||||
| one.next = two | ||||
| two.next = three | ||||
| 
 | ||||
| print(one) | ||||
| delete(two) | ||||
| print(one) | ||||
							
								
								
									
										38
									
								
								scratch/facebook/dijkstras.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								scratch/facebook/dijkstras.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | |||
| from heapq import heappush, heappop | ||||
| import random | ||||
| 
 | ||||
| # Dijkstra's algorithm will traverse a directed graph with weighted edges. If | ||||
| # the edges aren't weighted, we can pretend that each edges weighs 1. The | ||||
| # algorithm will find the shortest path between points A and B. | ||||
| 
 | ||||
| def dijkstra(a, b, graph): | ||||
|     h = [] | ||||
|     seen = set() | ||||
|     heappush(h, (0, a, [a], [])) | ||||
|     while h: | ||||
|         km, x, path, steps = heappop(h) | ||||
| 
 | ||||
|         if x == b: | ||||
|             for a, b, d in steps: | ||||
|                 print("{} -> {} => {}".format(a, b, d)) | ||||
|             return path, km | ||||
| 
 | ||||
|         seen.add(x) | ||||
|         for c, dist in graph[x]: | ||||
|             if c not in seen: | ||||
|                 heappush(h, (km + dist, c, path + [c], steps + [(x, c, dist)])) | ||||
|     return [], float('inf') | ||||
| 
 | ||||
| graph = { | ||||
|     1: [(3, 9), (2, 7), (6, 14)], | ||||
|     2: [(1, 7), (3, 10), (4, 15)], | ||||
|     3: [(1, 9), (6, 2), (4, 11), (2, 10)], | ||||
|     4: [(5, 6), (2, 15), (3, 11)], | ||||
|     5: [(4, 6), (6, 9)], | ||||
|     6: [(5, 9), (3, 2), (1, 14)], | ||||
| } | ||||
| 
 | ||||
| beg = random.choice(list(graph.keys())) | ||||
| end = random.choice(list(graph.keys())) | ||||
| print("Searching for the shortest path from {} -> {}".format(beg, end)) | ||||
| print(dijkstra(beg, end, graph)) | ||||
							
								
								
									
										39
									
								
								scratch/facebook/evaluator.hs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								scratch/facebook/evaluator.hs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | |||
| module Evaluator where | ||||
| 
 | ||||
| data Token | ||||
|   = TokenInt Integer | ||||
|   | TokenAdd | ||||
|   | TokenMultiply | ||||
|   deriving (Eq, Show) | ||||
| 
 | ||||
| newtype AST = AST [Token] | ||||
|   deriving (Eq, Show) | ||||
| 
 | ||||
| tokens :: [Token] | ||||
| tokens = | ||||
|   [ TokenInt 13 | ||||
|   , TokenAdd | ||||
|   , TokenInt 2 | ||||
|   , TokenMultiply | ||||
|   , TokenInt 4 | ||||
|   , TokenAdd | ||||
|   , TokenInt 7 | ||||
|   , TokenAdd | ||||
|   , TokenInt 3 | ||||
|   , TokenMultiply | ||||
|   , TokenInt 8 | ||||
|   ] | ||||
| 
 | ||||
| -- expression     -> addition ; | ||||
| -- addition       -> multiplication ( "+" multiplication )* ; | ||||
| -- multiplication -> terminal ( "*" terminal )* ; | ||||
| -- terminal       -> NUMBER ; | ||||
| 
 | ||||
| parseExpression :: [Token] -> ([Token], AST) | ||||
| parseExpression tokens = do | ||||
|   lhs, rest = parseMultiplication tokens | ||||
| 
 | ||||
| parseMulitplication :: [Token] -> ([Token], AST) | ||||
| 
 | ||||
| main :: IO () | ||||
| main = print $ parse tokens | ||||
							
								
								
									
										234
									
								
								scratch/facebook/evaluator.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								scratch/facebook/evaluator.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,234 @@ | |||
| # After stumbling through my first technical screen, I'm going to drill | ||||
| # algorithms for implementing evaluators for a toy expression language: | ||||
| # e.g. 2 + 13 * 3 + 5 * 2 | ||||
| # | ||||
| # As of now, I'm aware of a few algorithms for solving this: | ||||
| #   - DONE: Convert infix expression to Polish notation and evaluate the Polish | ||||
| #     notation. | ||||
| #   - DONE: Evaluate the tokens using two stacks and avoid converting it. | ||||
| #   - DONE: Create a tree of depth two to encode the operator precedence and | ||||
| #     evaluate that AST. | ||||
| #   - TODO: Convert the infix expression to a prefix expression | ||||
| #   - TODO: Write a recursive descent parser and evaluate the AST. | ||||
| 
 | ||||
| operators = { | ||||
|     '*': 1, | ||||
|     '+': 0, | ||||
| } | ||||
| 
 | ||||
| def tokenize(xs): | ||||
|     result = [] | ||||
|     i = 0 | ||||
|     while i < len(xs): | ||||
|         current = xs[i] | ||||
|         if current == ' ': | ||||
|             i += 1 | ||||
|             continue | ||||
|         elif current in operators.keys(): | ||||
|             result.append(current) | ||||
|             i += 1 | ||||
|         else: | ||||
|             i += 1 | ||||
|             while i < len(xs) and xs[i] in {str(n) for n in range(10)}: | ||||
|                 current += xs[i] | ||||
|                 i += 1 | ||||
|             result.append(int(current)) | ||||
|     return result | ||||
| 
 | ||||
| # Convert infix to postfix; evaluate postfix | ||||
| # I believe this is known as the Shunting-Yards algorithm | ||||
| def postfix(tokens): | ||||
|     result = [] | ||||
|     s = [] | ||||
|     for token in tokens: | ||||
|         if type(token) == int: | ||||
|             result.append(token) | ||||
|         else: | ||||
|             while s and operators[token] < operators[s[-1]]: | ||||
|                 result.append(s.pop()) | ||||
|             s.append(token) | ||||
|     while s: | ||||
|         result.append(s.pop()) | ||||
|     return result | ||||
| 
 | ||||
| def do_evaluate_with_polish_notation(tokens): | ||||
|     s = [] | ||||
|     for token in tokens: | ||||
|         if token == '*': | ||||
|             s.append(s.pop() * s.pop()) | ||||
|         elif token == '+': | ||||
|             s.append(s.pop() + s.pop()) | ||||
|         else: | ||||
|             s.append(token) | ||||
|     return s[-1] | ||||
| 
 | ||||
| def evaluate_with_polish_notation(expr): | ||||
|     tokens = tokenize(expr) | ||||
|     print("Tokens:  {}".format(tokens)) | ||||
|     pn = postfix(tokens) | ||||
|     print("Postfix: {}".format(pn)) | ||||
|     result = do_evaluate_with_polish_notation(pn) | ||||
|     print("Result:  {}".format(result)) | ||||
|     return result | ||||
| 
 | ||||
| # Evaluate Tokens | ||||
| 
 | ||||
| def apply_operator(op, a, b): | ||||
|     if op == '*': | ||||
|         return a * b | ||||
|     elif op == '+': | ||||
|         return a + b | ||||
| 
 | ||||
| def do_evaluate_tokens(tokens): | ||||
|     vals = [] | ||||
|     ops = [] | ||||
|     for token in tokens: | ||||
|         if type(token) == int: | ||||
|             vals.append(token) | ||||
|         elif token == '*': | ||||
|             ops.append(token) | ||||
|         elif token == '+': | ||||
|             while ops and operators[token] < operators[ops[-1]]: | ||||
|                 vals.append(apply_operator(ops.pop(), vals.pop(), vals.pop())) | ||||
|             ops.append(token) | ||||
|         else: | ||||
|             raise Exception("Unexpected token: {}".format(token)) | ||||
|     while ops: | ||||
|         vals.append(apply_operator(ops.pop(), vals.pop(), vals.pop())) | ||||
|     return vals[-1] | ||||
| 
 | ||||
| def evaluate_tokens(expr): | ||||
|     tokens = tokenize(expr) | ||||
|     print("Tokens:  {}".format(tokens)) | ||||
|     result = do_evaluate_tokens(tokens) | ||||
|     print("Result:  {}".format(result)) | ||||
|     return result | ||||
| 
 | ||||
| # Ad Hoc Tree | ||||
| 
 | ||||
| def parse(tokens): | ||||
|     result = [] | ||||
|     series = [] | ||||
|     for token in tokens: | ||||
|         if type(token) == int: | ||||
|             series.append(token) | ||||
|         elif token == '*': | ||||
|             continue | ||||
|         elif token == '+': | ||||
|             result.append(series) | ||||
|             series = [] | ||||
|         else: | ||||
|             raise Exception("Unexpected token: {}".format(token)) | ||||
|     result.append(series) | ||||
|     return result | ||||
| 
 | ||||
| def product(xs): | ||||
|     result = 1 | ||||
|     for x in xs: | ||||
|         result *= x | ||||
|     return result | ||||
| 
 | ||||
| def do_evaluate_ad_hoc_tree(ast): | ||||
|     return sum([product(xs) for xs in ast]) | ||||
| 
 | ||||
| def evaluate_ad_hoc_tree(expr): | ||||
|     tokens = tokenize(expr) | ||||
|     print("Tokens:  {}".format(tokens)) | ||||
|     ast = parse(tokens) | ||||
|     print("AST:     {}".format(ast)) | ||||
|     result = do_evaluate_ad_hoc_tree(ast) | ||||
|     print("Result:  {}".format(result)) | ||||
|     return result | ||||
| 
 | ||||
| # Recursive Descent Parser | ||||
| 
 | ||||
| # expression     -> addition ; | ||||
| # addition       -> multiplication ( "+" multiplication )* ; | ||||
| # multiplication -> terminal ( "*" terminal )* ; | ||||
| # terminal       -> NUMBER ; | ||||
| 
 | ||||
| class Parser(object): | ||||
|     def __init__(self, tokens): | ||||
|         self.tokens = tokens | ||||
|         self.i = 0 | ||||
| 
 | ||||
|     # mutations | ||||
|     def advance(self): | ||||
|         self.i += 1 | ||||
| 
 | ||||
|     def consume(self): | ||||
|         result = self.curr() | ||||
|         self.advance() | ||||
|         return result | ||||
| 
 | ||||
|     # predicates | ||||
|     def match(self, x): | ||||
|         if self.curr() == x: | ||||
|             self.advance() | ||||
|             return True | ||||
|         return False | ||||
| 
 | ||||
|     def tokens_available(self): | ||||
|         return self.i < len(self.tokens) | ||||
| 
 | ||||
|     # getters | ||||
|     def prev(self): | ||||
|         return self.tokens[self.i - 1] | ||||
| 
 | ||||
|     def curr(self): | ||||
|         return self.tokens[self.i] if self.tokens_available() else None | ||||
| 
 | ||||
|     def next(self): | ||||
|         return self.tokens[self.i + 1] | ||||
| 
 | ||||
| def parse_expression(tokens): | ||||
|     parser = Parser(tokens) | ||||
|     return parse_addition(parser) | ||||
| 
 | ||||
| def parse_addition(parser): | ||||
|     result = parse_multiplication(parser) | ||||
|     while parser.match("+"): | ||||
|         op = parser.prev() | ||||
|         rhs = parse_multiplication(parser) | ||||
|         result = ["+", result, rhs] | ||||
|     return result | ||||
| 
 | ||||
| def parse_multiplication(parser): | ||||
|     result = parse_terminal(parser) | ||||
|     while parser.match("*"): | ||||
|         op = parser.prev() | ||||
|         rhs = parse_terminal(parser) | ||||
|         result = ["*", result, rhs] | ||||
|     return result | ||||
| 
 | ||||
| def parse_terminal(parser): | ||||
|     # If we reach here, the current token *must* be a number. | ||||
|     return parser.consume() | ||||
| 
 | ||||
| def evaluate_ast(ast): | ||||
|     if type(ast) == int: | ||||
|         return ast | ||||
|     else: | ||||
|         op, lhs, rhs = ast[0], ast[1], ast[2] | ||||
|         return apply_operator(op, evaluate_ast(lhs), evaluate_ast(rhs)) | ||||
| 
 | ||||
| def evaluate_recursive_descent(expr): | ||||
|     tokens = tokenize(expr) | ||||
|     print("Tokens:  {}".format(tokens)) | ||||
|     ast = parse_expression(tokens) | ||||
|     print("AST:     {}".format(ast)) | ||||
|     result = evaluate_ast(ast) | ||||
|     return result | ||||
| 
 | ||||
| methods = { | ||||
|     'Polish Notation': evaluate_with_polish_notation, | ||||
|     'Evaluate Tokens': evaluate_tokens, | ||||
|     'Ad Hoc Tree': evaluate_ad_hoc_tree, | ||||
|     'Recursive Descent': evaluate_recursive_descent, | ||||
| } | ||||
| 
 | ||||
| for name, fn in methods.items(): | ||||
|     expr = "13 + 2 * 4 + 7 + 3 * 8" | ||||
|     print("Evaluating \"{}\" using the \"{}\" method...".format(expr, name)) | ||||
|     assert fn(expr) == eval(expr) | ||||
|     print("Success!") | ||||
							
								
								
									
										22
									
								
								scratch/facebook/find-duplicate-optimize-for-space.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								scratch/facebook/find-duplicate-optimize-for-space.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| import random | ||||
| 
 | ||||
| def find_duplicate(xs): | ||||
|     print(xs) | ||||
|     # entry point in our cycle is the duplicate | ||||
|     i = xs[0] | ||||
|     j = xs[xs[0]] | ||||
|     while i != j: | ||||
|         print(i, xs[i], j, xs[j]) | ||||
|         i = xs[i] | ||||
|         j = xs[xs[j]] | ||||
|     # detect cycle | ||||
|     j = 0 | ||||
|     while i != j: | ||||
|         i = xs[i] | ||||
|         j = xs[j] | ||||
|     return xs[i] | ||||
| 
 | ||||
| n = random.randint(5, 10) | ||||
| xs = [random.randint(0, n - 1) for _ in range(n)] | ||||
| result = find_duplicate(xs) | ||||
| print(xs, result) | ||||
							
								
								
									
										47
									
								
								scratch/facebook/find-rotation-point.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								scratch/facebook/find-rotation-point.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| from math import floor | ||||
| 
 | ||||
| def find_rotation(xs): | ||||
|     if xs[0] < xs[-1]: | ||||
|         return xs[0] | ||||
|     beg, end = 0, len(xs) - 1 | ||||
|     found = False | ||||
|     count = 10 | ||||
|     while not found and count >= 0: | ||||
|         i = beg + floor((end - beg) / 2) | ||||
|         if xs[beg] < xs[i]: | ||||
|             beg = i | ||||
|             i = beg + floor((end - beg) / 2) | ||||
|         elif xs[beg] > xs[i]: | ||||
|             end = i | ||||
|         found = xs[i - 1] > xs[i] | ||||
|         count -= 1 | ||||
|     return xs[i] | ||||
| 
 | ||||
| 
 | ||||
| xs = [(['ptolemaic', | ||||
|         'retrograde', | ||||
|         'supplant', | ||||
|         'undulate', | ||||
|         'xenoepist', | ||||
|         'zebra', | ||||
|         'asymptote', | ||||
|         'babka', | ||||
|         'banoffee', | ||||
|         'engender', | ||||
|         'karpatka', | ||||
|         'othellolagkage', | ||||
|         ], "asymptote"), | ||||
|       (['asymptote', | ||||
|         'babka', | ||||
|         'banoffee', | ||||
|         'engender', | ||||
|         'karpatka', | ||||
|         'othellolagkage', | ||||
|         ], "asymptote"), | ||||
|       ] | ||||
| 
 | ||||
| for x, expected in xs: | ||||
|     result = find_rotation(x) | ||||
|     print(x, result) | ||||
|     assert result == expected | ||||
|     print("Success!") | ||||
							
								
								
									
										17
									
								
								scratch/facebook/find-unique-int-among-duplicates.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								scratch/facebook/find-unique-int-among-duplicates.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| import random | ||||
| 
 | ||||
| def find_duplicate(xs): | ||||
|     mini, maxi, acc = xs[0], xs[0], xs[0] | ||||
|     for i in range(1, len(xs)): | ||||
|         mini = min(mini, xs[i]) | ||||
|         maxi = max(maxi, xs[i]) | ||||
|         acc = acc ^ xs[i] | ||||
|     mask = mini | ||||
|     for i in range(mini + 1, maxi + 1): | ||||
|         mask = mask ^ i | ||||
|     return mask ^ acc | ||||
| 
 | ||||
| xs = [5, 3, 4, 1, 5, 2] | ||||
| print(xs) | ||||
| result = find_duplicate(xs) | ||||
| print(result) | ||||
							
								
								
									
										60
									
								
								scratch/facebook/graph-coloring.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								scratch/facebook/graph-coloring.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| from collections import deque | ||||
| 
 | ||||
| class Palette(object): | ||||
|     def __init__(self, n): | ||||
|         self.i = 0 | ||||
|         self.colors = list(range(n)) | ||||
| 
 | ||||
|     def get(self): | ||||
|         return self.colors[self.i] | ||||
| 
 | ||||
|     def advance(self): | ||||
|         self.i += 1 % len(self.colors) | ||||
| 
 | ||||
| class GraphNode(object): | ||||
|     def __init__(self, label): | ||||
|         self.label = label | ||||
|         self.neighbors = set() | ||||
|         self.color = None | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         result = [] | ||||
|         xs = deque() | ||||
|         xs.append(self) | ||||
|         seen = set() | ||||
|         while xs: | ||||
|             node = xs.popleft() | ||||
|             result.append('{} ({})'.format(node.label, str(node.color))) | ||||
|             seen.add(node.label) | ||||
|             for c in node.neighbors: | ||||
|                 if c.label not in seen: | ||||
|                     xs.append(c) | ||||
|         return ', '.join(result) | ||||
| 
 | ||||
| def color_graph(graph, d): | ||||
|     seen = set() | ||||
|     start = graph | ||||
|     xs = deque() | ||||
|     palette = Palette(d + 1) | ||||
|     xs.append((start, palette.get())) | ||||
|     while xs: | ||||
|         x, color = xs.popleft() | ||||
|         x.color = color | ||||
|         seen.add(x.label) | ||||
|         for c in x.neighbors: | ||||
|             if c.label not in seen: | ||||
|                 palette.advance() | ||||
|                 xs.append((c, palette.get())) | ||||
| 
 | ||||
| a = GraphNode('a') | ||||
| b = GraphNode('b') | ||||
| c = GraphNode('c') | ||||
| 
 | ||||
| a.neighbors.add(b) | ||||
| b.neighbors.add(a) | ||||
| b.neighbors.add(c) | ||||
| c.neighbors.add(b) | ||||
| 
 | ||||
| print(a) | ||||
| color_graph(a, 3) | ||||
| print(a) | ||||
							
								
								
									
										20
									
								
								scratch/facebook/highest-product-of-3.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								scratch/facebook/highest-product-of-3.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| def hi_product(xs): | ||||
|     lowest_one, highest_one = min(xs[0], xs[1]), max(xs[0], xs[1]) | ||||
|     lowest_two, highest_two = xs[0] * xs[1], xs[0] * xs[1] | ||||
|     highest = float('-inf') | ||||
|     for x in xs[2:]: | ||||
|         highest = max(highest, highest_two * x, lowest_two * x) | ||||
|         lowest_one = min(lowest_one, x) | ||||
|         highest_one = max(highest_one, x) | ||||
|         lowest_two = min(lowest_two, highest_one * x, lowest_one * x) | ||||
|         highest_two = max(highest_two, highest_one * x, lowest_one * x) | ||||
|     return highest | ||||
| 
 | ||||
| xs = [([-10,-10,1,3,2], 300), | ||||
|       ([1,10,-5,1,-100], 5000)] | ||||
| 
 | ||||
| for x, expected in xs: | ||||
|     result = hi_product(x) | ||||
|     print(x, result) | ||||
|     assert result == expected | ||||
|     print("Success!") | ||||
							
								
								
									
										51
									
								
								scratch/facebook/infix-to-postfix.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								scratch/facebook/infix-to-postfix.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,51 @@ | |||
| operators = { | ||||
|     '*': 1, | ||||
|     '+': 0, | ||||
| } | ||||
| 
 | ||||
| def tokenize(xs): | ||||
|     result = [] | ||||
|     i = 0 | ||||
|     while i < len(xs): | ||||
|         current = xs[i] | ||||
|         if current in operators.keys(): | ||||
|             result.append(current) | ||||
|             i += 1 | ||||
|             continue | ||||
|         else: | ||||
|             i += 1 | ||||
|             while i < len(xs) and xs[i] in {str(n) for n in range(10)}: | ||||
|                 current += xs[i] | ||||
|                 i += 1 | ||||
|             result.append(int(current)) | ||||
|     return result | ||||
| 
 | ||||
| def postfix(xs): | ||||
|     result = [] | ||||
|     s = [] | ||||
|     for x in xs: | ||||
|         if x in operators.keys(): | ||||
|             while s and operators[s[-1]] >= operators[x]: | ||||
|                 result.append(s.pop()) | ||||
|             s.append(x) | ||||
|         else: | ||||
|             result.append(x) | ||||
|     while s: | ||||
|         result.append(s.pop()) | ||||
|     return result | ||||
| 
 | ||||
| def evaluate(xs): | ||||
|     s = [] | ||||
|     for x in xs: | ||||
|         print(s, x) | ||||
|         if x == '*': | ||||
|             s.append(s.pop() * s.pop()) | ||||
|         elif x == '+': | ||||
|             s.append(s.pop() + s.pop()) | ||||
|         else: | ||||
|             s.append(x) | ||||
|         print(s) | ||||
|     return s[-1] | ||||
| 
 | ||||
| 
 | ||||
| print(evaluate(postfix(tokenize("12+3*10")))) | ||||
							
								
								
									
										29
									
								
								scratch/facebook/inflight-entertainment.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								scratch/facebook/inflight-entertainment.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | |||
| from random import choice | ||||
| from utils import init_table | ||||
| 
 | ||||
| def get(movie, seeking): | ||||
|     return any([movie in xs for xs in seeking.values()]) | ||||
| 
 | ||||
| def set_complement(movie, seeking): | ||||
|     for duration, xs in seeking.items(): | ||||
|         seeking[duration].add(duration - movie) | ||||
| 
 | ||||
| def choose_movies(tolerance, duration, movies): | ||||
|     seeking = {duration + i: set() for i in range(-1 * tolerance, tolerance + 1)} | ||||
|     for movie in movies: | ||||
|         if get(movie, seeking): | ||||
|             return movie, duration - movie | ||||
|         else: | ||||
|             set_complement(movie, seeking) | ||||
|     return None | ||||
| 
 | ||||
| tolerance = 20 | ||||
| duration = choice([1, 2, 3]) * choice([1, 2]) * choice([15, 30, 45]) | ||||
| movies = [choice([1, 2, 3]) * choice([15, 30, 45]) for _ in range(10)] | ||||
| print("Seeking two movies for a duration of [{}, {}] minutes".format(duration - tolerance, duration + tolerance)) | ||||
| print(movies) | ||||
| result = choose_movies(tolerance, duration, movies) | ||||
| if result: | ||||
|     print("{} + {} = {}".format(result[0], result[1], duration)) | ||||
| else: | ||||
|     print(":( We're sad because we couldn't find two movies for a {} minute flight".format(duration)) | ||||
							
								
								
									
										42
									
								
								scratch/facebook/knapsack-faq.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								scratch/facebook/knapsack-faq.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| from utils import get, init_table, print_table | ||||
| 
 | ||||
| # This problem has a few variants: | ||||
| #   - limited supply of each item | ||||
| #   - unlimited supply of each item | ||||
| #   - fractional amounts of each item (e.g. rice) | ||||
| 
 | ||||
| def max_haul(capacity, items): | ||||
|     min_kg = min([kg for _, kg in items]) | ||||
|     max_kg = max([kg for _, kg in items]) | ||||
| 
 | ||||
|     cols = int(max_kg / min_kg) | ||||
|     fr_col_index = lambda index: min_kg * index + min_kg | ||||
|     to_col_index = lambda capacity: int((capacity - min_kg) * cols / max_kg) | ||||
| 
 | ||||
|     table = init_table(rows=len(items), cols=cols, default=0) | ||||
|     for row in range(len(table)): | ||||
|         for col in range(len(table[row])): | ||||
|             curr_capacity = fr_col_index(col) | ||||
|             value, kg = items[row] | ||||
| 
 | ||||
|             if kg > curr_capacity: | ||||
|                 a = 0 | ||||
|             else: | ||||
|                 a = value + get(table, row - 1, to_col_index(curr_capacity - kg)) | ||||
| 
 | ||||
|             b = get(table, row - 1, col) | ||||
|             table[row][col] = max([a, b]) | ||||
|         print_table(table) | ||||
|     return table[-1][-1] | ||||
| 
 | ||||
| guitar = (1500, 1) | ||||
| stereo = (3000, 4) | ||||
| laptop = (2000, 3) | ||||
| necklace = (2000, 0.5) | ||||
| items = [necklace, guitar, stereo, laptop] | ||||
| capacity = 4 | ||||
| result = max_haul(capacity, items) | ||||
| expected = 4000 | ||||
| print(result, expected) | ||||
| assert result == expected | ||||
| print("Success!") | ||||
							
								
								
									
										26
									
								
								scratch/facebook/kth-to-last-node-in-singly-linked-list.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								scratch/facebook/kth-to-last-node-in-singly-linked-list.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| from linked_list import Node, from_list | ||||
| 
 | ||||
| def kth_to_last_node(k, node): | ||||
|     one = node | ||||
|     two = node | ||||
|     for _ in range(k - 1): | ||||
|         if not one: | ||||
|             return None | ||||
|         one = one.next | ||||
|     while one.next: | ||||
|         one = one.next | ||||
|         two = two.next | ||||
|     return two.value | ||||
| 
 | ||||
| 
 | ||||
| xs = from_list(["Angel Food", "Bundt", "Cheese", "Devil's Food", "Eccles"]) | ||||
| result = kth_to_last_node(2, xs) | ||||
| print(result) | ||||
| assert result == "Devil's Food" | ||||
| print("Success!") | ||||
| 
 | ||||
| xs = from_list(["Angel Food", "Bundt"]) | ||||
| result = kth_to_last_node(30, xs) | ||||
| print(result) | ||||
| assert result is None | ||||
| print("Success!") | ||||
							
								
								
									
										70
									
								
								scratch/facebook/language.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								scratch/facebook/language.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| import random | ||||
| 
 | ||||
| # Write an evaluator for a small language: | ||||
| #   - operators: '+', '*' | ||||
| #   - operands:  Integers | ||||
| # | ||||
| # E.g. evaluate("2+14*90+5*16") | ||||
| 
 | ||||
| def tokenize(xs): | ||||
|     result = [] | ||||
|     i = 0 | ||||
|     while i < len(xs): | ||||
|         current = xs[i] | ||||
|         if current in {'*', '+'}: | ||||
|             result.append(current) | ||||
|             i += 1 | ||||
|             continue | ||||
|         elif current == ' ': | ||||
|             i += 1 | ||||
|             continue | ||||
|         else: | ||||
|             i += 1 | ||||
|             while i < len(xs) and xs[i] in {str(x) for x in range(10)}: | ||||
|                 current += xs[i] | ||||
|                 i += 1 | ||||
|             result.append(int(current)) | ||||
|     return result | ||||
| 
 | ||||
| def ast(tokens): | ||||
|     result = [] | ||||
|     series = [] | ||||
|     for token in tokens: | ||||
|         if token == '+': | ||||
|             result.append(series) | ||||
|             series = [] | ||||
|         elif token == '*': | ||||
|             continue | ||||
|         else: | ||||
|             series.append(token) | ||||
|     if series: | ||||
|         result.append(series) | ||||
|     return result | ||||
| 
 | ||||
| def product(xs): | ||||
|     result = 1 | ||||
|     for x in xs: | ||||
|         result *= x | ||||
|     return result | ||||
| 
 | ||||
| def evaluate(x): | ||||
|     tokens = tokenize(x) | ||||
|     tree = ast(tokens) | ||||
|     return sum([product(xs) for xs in tree]) | ||||
| 
 | ||||
| n = 7 | ||||
| operands = [random.randint(0, 100) for _ in range(n)] | ||||
| operators = [random.choice(['+','*']) for _ in range(n - 1)] | ||||
| expr = [] | ||||
| for i in range(n - 1): | ||||
|     expr.append(operands[i]) | ||||
|     expr.append(operators[i]) | ||||
| expr.append(operands[-1]) | ||||
| 
 | ||||
| expr = ' '.join([str(x) for x in expr]) | ||||
| print("Expression: {}".format(expr)) | ||||
| print("Tokens: {}".format(tokenize(expr))) | ||||
| print("AST: {}".format(ast(tokenize(expr)))) | ||||
| print("Answer: {}".format(evaluate(expr))) | ||||
| assert evaluate(expr) == eval(expr) | ||||
| print("Success!") | ||||
							
								
								
									
										50
									
								
								scratch/facebook/language2.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								scratch/facebook/language2.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| def tokenize(xs): | ||||
|     result = [] | ||||
|     i = 0 | ||||
|     while i < len(xs): | ||||
|         curr = xs[i] | ||||
|         if curr in {'*','+'}: | ||||
|             result.append(curr) | ||||
|             i += 1 | ||||
|             continue | ||||
|         i += 1 | ||||
|         while i < len(xs) and xs[i] in {str(x) for x in range(10)}: | ||||
|             curr += xs[i] | ||||
|             i += 1 | ||||
|         result.append(int(curr)) | ||||
|     return result | ||||
| 
 | ||||
| def parse(tokens): | ||||
|     result = [] | ||||
|     series = [] | ||||
|     for token in tokens: | ||||
|         if token == '*': | ||||
|             continue | ||||
|         elif token == '+': | ||||
|             result.append(series) | ||||
|             series = [] | ||||
|         else: | ||||
|             series.append(token) | ||||
|     if series: | ||||
|         result.append(series) | ||||
|     return result | ||||
| 
 | ||||
| def product(xs): | ||||
|     result = 1 | ||||
|     for x in xs: | ||||
|         result *= x | ||||
|     return result | ||||
| 
 | ||||
| def evaluate(tree): | ||||
|     return sum([product(xs) for xs in tree]) | ||||
| 
 | ||||
| print(evaluate(parse(tokenize("2+30*8*9+10")))) | ||||
							
								
								
									
										15
									
								
								scratch/facebook/largest-contiguous-sum.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								scratch/facebook/largest-contiguous-sum.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | |||
| def find_sum(xs): | ||||
|     result = float('-inf') | ||||
|     streak = 0 | ||||
|     for x in xs: | ||||
|         result = max(result, streak, x) | ||||
|         if streak + x <= 0: | ||||
|             streak = x | ||||
|         else: | ||||
|             streak += x | ||||
|     return result | ||||
| 
 | ||||
| 
 | ||||
| x = [2,-8,3,-2,4,-10] | ||||
| assert find_sum(x) == 5 | ||||
| print("Success!") | ||||
							
								
								
									
										49
									
								
								scratch/facebook/largest-stack.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								scratch/facebook/largest-stack.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | |||
| from stack import Stack, from_list | ||||
| from heapq import heapify, heappush, heappop | ||||
| from random import shuffle | ||||
| 
 | ||||
| class MaxStack(Stack): | ||||
|     def __init__(self): | ||||
|         self.max = Stack() | ||||
|         super().__init__() | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         return super().__repr__() | ||||
| 
 | ||||
|     def push(self, x): | ||||
|         super().push(x) | ||||
|         max = self.get_max() | ||||
|         if not max: | ||||
|             self.max.push(x) | ||||
|         else: | ||||
|             self.max.push(max if x < max else x) | ||||
| 
 | ||||
|     def pop(self): | ||||
|         self.max.pop() | ||||
|         return super().pop() | ||||
| 
 | ||||
|     def get_max(self): | ||||
|         return self.max.peek() | ||||
| 
 | ||||
| xs = list(range(1, 11)) | ||||
| shuffle(xs) | ||||
| stack = MaxStack() | ||||
| for x in xs: | ||||
|     stack.push(x) | ||||
| 
 | ||||
| print(stack) | ||||
| result = stack.get_max() | ||||
| print(result) | ||||
| assert result == 10 | ||||
| 
 | ||||
| popped = stack.pop() | ||||
| print("Popped: {}".format(popped)) | ||||
| print(stack) | ||||
| while popped != 10: | ||||
|     assert stack.get_max() == 10 | ||||
|     popped = stack.pop() | ||||
|     print("Popped: {}".format(popped)) | ||||
|     print(stack) | ||||
| 
 | ||||
| assert stack.get_max() != 10 | ||||
| print("Success!") | ||||
							
								
								
									
										26
									
								
								scratch/facebook/linked-list-cycles.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								scratch/facebook/linked-list-cycles.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| import random | ||||
| 
 | ||||
| from linked_list import Node | ||||
| 
 | ||||
| def contains_cycle(node): | ||||
|     one = node | ||||
|     two = node | ||||
|     while two.next and two.next.next: | ||||
|         one = one.next | ||||
|         two = two.next.next | ||||
|         if one == two: | ||||
|             return True | ||||
|     return False | ||||
| 
 | ||||
| xs = Node(1, Node(2, Node(3))) | ||||
| assert not contains_cycle(xs) | ||||
| print("Success!") | ||||
| 
 | ||||
| a = Node(1) | ||||
| b = Node(2) | ||||
| c = Node(3) | ||||
| a.next = b | ||||
| b.next = c | ||||
| c.next = random.choice([a, b, c]) | ||||
| assert contains_cycle(a) | ||||
| print("Success!") | ||||
							
								
								
									
										22
									
								
								scratch/facebook/linked_list.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								scratch/facebook/linked_list.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| class Node(object): | ||||
|     def __init__(self, value=None, next=None): | ||||
|         self.value = value | ||||
|         self.next = next | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         result = [] | ||||
|         node = self | ||||
|         while node: | ||||
|             result.append(str(node.value)) | ||||
|             node = node.next | ||||
|         return 'LinkedList({xs})'.format(xs=', '.join(result)) | ||||
| 
 | ||||
| def from_list(xs): | ||||
|     head = Node(xs[0]) | ||||
|     node = head | ||||
|     for x in xs[1:]: | ||||
|         node.next = Node(x) | ||||
|         node = node.next | ||||
|     return head | ||||
| 
 | ||||
| list = from_list(['A', 'B', 'C']) | ||||
							
								
								
									
										42
									
								
								scratch/facebook/london-knapsack.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								scratch/facebook/london-knapsack.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| from utils import get, init_table, print_table | ||||
| 
 | ||||
| def optimal_itinerary(duration, items): | ||||
|     min_duration = min([duration for duration, _ in items]) | ||||
|     max_duration = max([duration for duration, _ in items]) | ||||
|     table = init_table(rows=len(items), cols=int(max_duration / min_duration), default=0) | ||||
|     to_index = lambda duration: int(duration / min_duration) - 1 | ||||
|     to_duration = lambda i: i * min_duration + min_duration | ||||
| 
 | ||||
|     for row in range(len(table)): | ||||
|         for col in range(len(table[row])): | ||||
|             curr_duration = to_duration(col) | ||||
|             duration, value = items[row] | ||||
|             if duration > curr_duration: | ||||
|                 a = 0 | ||||
|             else: | ||||
|                 a = value + get(table, row - 1, to_index(curr_duration - duration)) | ||||
|             b = get(table, row - 1, col) | ||||
|             table[row][col] = max([a, b]) | ||||
| 
 | ||||
|         print_table(table) | ||||
|     return table[-1][-1] | ||||
| 
 | ||||
| # You're in London for two days, and you'd like to see the following | ||||
| # attractions. How can you maximize your time spent in London? | ||||
| westminster = (0.5, 7) | ||||
| globe_theater = (0.5, 6) | ||||
| national_gallery = (1, 9) | ||||
| british_museum = (2, 9) | ||||
| st_pauls_cathedral = (0.5, 8) | ||||
| items = [ | ||||
|     westminster, | ||||
|     globe_theater, | ||||
|     national_gallery, | ||||
|     british_museum, | ||||
|     st_pauls_cathedral, | ||||
| ] | ||||
| result = optimal_itinerary(2, items) | ||||
| expected = 24 | ||||
| print(result, expected) | ||||
| assert result == expected | ||||
| print("Success!") | ||||
							
								
								
									
										20
									
								
								scratch/facebook/longest-common-substring.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								scratch/facebook/longest-common-substring.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| from utils import get, init_table, print_table | ||||
| 
 | ||||
| def longest_common_substring(a, b): | ||||
|     """ | ||||
|     Computes the length of the longest string that's present in both `a` and | ||||
|     `b`. | ||||
|     """ | ||||
|     table = init_table(rows=len(b), cols=len(a), default=0) | ||||
|     for row in range(len(table)): | ||||
|         for col in range(len(table[row])): | ||||
|             if b[row] == a[col]: | ||||
|                 table[row][col] = 1 + get(table, row - 1, col - 1) | ||||
|     return max([max(row) for row in table]) | ||||
| 
 | ||||
| dictionary = ["fish", "vista"] | ||||
| result = [longest_common_substring("hish", x) for x in dictionary] | ||||
| expected = [3, 2] | ||||
| print(result, expected) | ||||
| assert result == expected | ||||
| print("Success!") | ||||
							
								
								
									
										44
									
								
								scratch/facebook/merge-sorted-arrays.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								scratch/facebook/merge-sorted-arrays.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | |||
| def merge_sorted(xs, ys): | ||||
|     result = [] | ||||
|     i, j = 0, 0 | ||||
| 
 | ||||
|     while i < len(xs) and j < len(ys): | ||||
|         if xs[i] <= ys[j]: | ||||
|             result.append(xs[i]) | ||||
|             i += 1 | ||||
|         else: | ||||
|             result.append(ys[j]) | ||||
|             j += 1 | ||||
| 
 | ||||
|     while i < len(xs): | ||||
|         result.append(xs[i]) | ||||
|         i += 1 | ||||
| 
 | ||||
|     while j < len(ys): | ||||
|         result.append(ys[j]) | ||||
|         j += 1 | ||||
| 
 | ||||
|     return result | ||||
| 
 | ||||
| # A | ||||
| result = merge_sorted([3, 4, 6, 10, 11, 15], [1, 5, 8, 12, 14, 19]) | ||||
| print(result) | ||||
| assert result == [1, 3, 4, 5, 6, 8, 10, 11, 12, 14, 15, 19] | ||||
| 
 | ||||
| # B | ||||
| result = merge_sorted([], [1,2,3]) | ||||
| print(result) | ||||
| assert result == [1,2,3] | ||||
| 
 | ||||
| # C | ||||
| result = merge_sorted([1,2,3], []) | ||||
| print(result) | ||||
| assert result == [1,2,3] | ||||
| 
 | ||||
| # D | ||||
| result = merge_sorted([], []) | ||||
| print(result) | ||||
| assert result == [] | ||||
| 
 | ||||
| # Wahoo! | ||||
| print("Success!") | ||||
							
								
								
									
										23
									
								
								scratch/facebook/merging-ranges.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								scratch/facebook/merging-ranges.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | |||
| 
 | ||||
| def merge(xs): | ||||
|     xs.sort() | ||||
|     result = xs[0:1] | ||||
|     for a, b in xs[1:]: | ||||
|         y, z = result[-1] | ||||
|         if a <= z: | ||||
|             result[-1] = (y, max(b, z)) | ||||
|         else: | ||||
|             result.append((a, b)) | ||||
|     return result | ||||
| 
 | ||||
| inputs = [([(0,1),(3,5),(4,8),(10,12),(9,10)], [(0,1),(3,8),(9,12)]), | ||||
|           ([(1,2),(2,3)], [(1,3)]), | ||||
|           ([(1,5),(2,3)], [(1,5)]), | ||||
|           ([(1,10),(2,6),(3,5),(7,9)], [(1,10)]), | ||||
|           ] | ||||
| for x, expected in inputs: | ||||
|     result = merge(x) | ||||
|     print(x) | ||||
|     print(result) | ||||
|     assert result == expected | ||||
|     print("Success!") | ||||
							
								
								
									
										40
									
								
								scratch/facebook/mesh-message.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								scratch/facebook/mesh-message.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | |||
| from heapq import heappush, heappop | ||||
| import random | ||||
| 
 | ||||
| def shortest_path(a, b, graph): | ||||
|     seen = set() | ||||
|     h = [] | ||||
|     heappush(h, (0, a, [a])) | ||||
|     while h: | ||||
|         km, x, path = heappop(h) | ||||
|         if x == b: | ||||
|             return path | ||||
|         for c in graph[x]: | ||||
|             if c not in seen: | ||||
|                 heappush(h, (km + 1, c, path + [c])) | ||||
|     raise Exception("We were unable to find a path from {} to {}".format(a, b)) | ||||
| 
 | ||||
| graph = { | ||||
|     'Min'     : ['William', 'Jayden', 'Omar'], | ||||
|     'William' : ['Min', 'Noam'], | ||||
|     'Jayden'  : ['Min', 'Amelia', 'Ren', 'Noam'], | ||||
|     'Ren'     : ['Jayden', 'Omar'], | ||||
|     'Amelia'  : ['Jayden', 'Adam', 'Miguel'], | ||||
|     'Adam'    : ['Amelia', 'Miguel', 'Sofia', 'Lucas'], | ||||
|     'Miguel'  : ['Amelia', 'Adam', 'Liam', 'Nathan'], | ||||
|     'Noam'    : ['Nathan', 'Jayden', 'William'], | ||||
|     'Omar'    : ['Ren', 'Min', 'Scott'], | ||||
|     'Liam'    : ['Ren'], | ||||
|     'Nathan'  : ['Noam'], | ||||
|     'Scott'   : [], | ||||
| } | ||||
| 
 | ||||
| result = shortest_path('Jayden', 'Adam', graph) | ||||
| print(result) | ||||
| assert result == ['Jayden', 'Amelia', 'Adam'] | ||||
| print('Success!') | ||||
| 
 | ||||
| beg = random.choice(list(graph.keys())) | ||||
| end = random.choice(list(graph.keys())) | ||||
| print("Attempting to find the shortest path between {} and {}".format(beg, end)) | ||||
| print(shortest_path(beg, end, graph)) | ||||
							
								
								
									
										71
									
								
								scratch/facebook/mst.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								scratch/facebook/mst.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | |||
| from heapq import heappush, heappop | ||||
| import random | ||||
| 
 | ||||
| def to_vertex_list(graph): | ||||
|     result = {} | ||||
|     for a, b, kg in graph: | ||||
|         if a in result: | ||||
|             result[a].append((b, kg)) | ||||
|         else: | ||||
|             result[a] = [(b, kg)] | ||||
|         if b in result: | ||||
|             result[b].append((a, kg)) | ||||
|         else: | ||||
|             result[b] = [(a, kg)] | ||||
|     return result | ||||
| 
 | ||||
| def mst(graph): | ||||
|     graph = to_vertex_list(graph) | ||||
|     beg = random.choice(list(graph.keys())) | ||||
|     h = [] | ||||
|     result = [] | ||||
|     seen = set() | ||||
|     for c, kg in graph[beg]: | ||||
|         heappush(h, (kg, beg, c)) | ||||
|     while h: | ||||
|         kg, beg, end = heappop(h) | ||||
|         # detect cycles | ||||
|         if end in seen: | ||||
|             continue | ||||
|         # use the edge | ||||
|         seen.add(beg) | ||||
|         seen.add(end) | ||||
|         result.append((beg, end)) | ||||
|         for c, kg in graph[end]: | ||||
|             heappush(h, (kg, end, c)) | ||||
|     return result | ||||
| 
 | ||||
| graphs = [ | ||||
|     [ | ||||
|         ('A', 'B', 7), | ||||
|         ('A', 'D', 5), | ||||
|         ('B', 'D', 9), | ||||
|         ('E', 'D', 15), | ||||
|         ('F', 'D', 6), | ||||
|         ('F', 'G', 11), | ||||
|         ('F', 'E', 8), | ||||
|         ('G', 'E', 9), | ||||
|         ('C', 'E', 5), | ||||
|         ('B', 'E', 7), | ||||
|         ('B', 'C', 8), | ||||
|     ], | ||||
|     [ | ||||
|         ('A', 'B', 4), | ||||
|         ('A', 'C', 8), | ||||
|         ('B', 'C', 11), | ||||
|         ('B', 'E', 8), | ||||
|         ('C', 'D', 7), | ||||
|         ('C', 'F', 1), | ||||
|         ('D', 'E', 2), | ||||
|         ('D', 'F', 6), | ||||
|         ('E', 'G', 7), | ||||
|         ('E', 'H', 4), | ||||
|         ('F', 'H', 2), | ||||
|         ('G', 'H', 14), | ||||
|         ('G', 'I', 9), | ||||
|         ('H', 'I', 10), | ||||
|     ], | ||||
| ] | ||||
| 
 | ||||
| for graph in graphs: | ||||
|     print(mst(graph)) | ||||
							
								
								
									
										38
									
								
								scratch/facebook/node.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								scratch/facebook/node.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | |||
| class Node(object): | ||||
|     def __init__(self, value, left=None, right=None): | ||||
|         self.value = value | ||||
|         self.left = left | ||||
|         self.right = right | ||||
| 
 | ||||
|     def insert_left(self, value): | ||||
|         self.left = Node(value) | ||||
|         return self.left | ||||
| 
 | ||||
|     def insert_right(self, value): | ||||
|         self.right = Node(value) | ||||
|         return self.right | ||||
| 
 | ||||
| tree = Node( | ||||
|     50, | ||||
|     Node( | ||||
|         17, | ||||
|         Node( | ||||
|             12, | ||||
|             Node(9), | ||||
|             Node(14), | ||||
|         ), | ||||
|         Node( | ||||
|             23, | ||||
|             Node(19), | ||||
|         ), | ||||
|     ), | ||||
|     Node( | ||||
|         72, | ||||
|         Node( | ||||
|             54, | ||||
|             None, | ||||
|             Node(67) | ||||
|         ), | ||||
|         Node(76), | ||||
|     ), | ||||
| ) | ||||
							
								
								
									
										13
									
								
								scratch/facebook/nth-fibonacci.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								scratch/facebook/nth-fibonacci.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| # 0, 1, 1, 2, 3, 5 | ||||
| def fib(n): | ||||
|     if n < 0: | ||||
|         raise Exception("Need to supply an index that's >= 0. Not: {}".format(n)) | ||||
|     elif n in {0, 1}: | ||||
|         return n | ||||
|     state = [0, 1] | ||||
|     for i in range(1, n): | ||||
|         state[0], state[1] = state[1], state[0] + state[1] | ||||
|     return state[-1] | ||||
| 
 | ||||
| for i in range(10): | ||||
|     print("fib({}) => {}".format(i, fib(i))) | ||||
							
								
								
									
										22
									
								
								scratch/facebook/onsite.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								scratch/facebook/onsite.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| ** Behavior Interview ** | ||||
| - Can I work in an unstructured environment? | ||||
| - Do I have a growth mindset? | ||||
| - How do I handle conflict? | ||||
| - Am I empathic? | ||||
| - Am I a self-starter? | ||||
| - What is my communication style? | ||||
| - Do I persevere? | ||||
| - <forgot to write this one down> | ||||
| 
 | ||||
| ** Design Interview ** | ||||
| - requirement gathering, problem exploring | ||||
| - component analysis | ||||
| - quantitative analysis | ||||
| - trade-offs | ||||
| - bottlenecks, weaknesses | ||||
| - securing data (e.g. PII) | ||||
| 
 | ||||
| Consider: | ||||
| - pagination | ||||
| - push/pull requests | ||||
| - API design | ||||
							
								
								
									
										121
									
								
								scratch/facebook/parsing/json.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								scratch/facebook/parsing/json.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,121 @@ | |||
| from parser import Parser | ||||
| 
 | ||||
| # As an exercise to stress-test my understanding of recursive descent parsers, | ||||
| # I'm attempting to write a JSON parser without referencing any existing BNF | ||||
| # descriptions of JSON or existing JSON parser implementations. | ||||
| # | ||||
| # I'm only parsing a subset of JSON: enough to parse `sample`. Here is the BNF | ||||
| # that I wrote to describe my expected input: | ||||
| # | ||||
| # expression -> object | ||||
| # object     -> '{' ( STRING ':' expression ) ( ',' STRING ':' expression )* '}' | ||||
| #            |  array | ||||
| # array      -> '[' expression ( ',' expression )* ']' | ||||
| #            |  literal | ||||
| # literal    -> STRING | INT | ||||
| 
 | ||||
| def tokenize(xs): | ||||
|     """ | ||||
|     Return a list of tokens from the string input, `xs`. | ||||
|     """ | ||||
|     result = [] | ||||
|     i = 0 | ||||
|     while i < len(xs): | ||||
|         # single characters | ||||
|         if xs[i] in ",{}:[]": | ||||
|             result.append(xs[i]) | ||||
|             i += 1 | ||||
|         # strings | ||||
|         elif xs[i] == "\"": | ||||
|             curr = xs[i] | ||||
|             i += 1 | ||||
|             while xs[i] != "\"": | ||||
|                 curr += xs[i] | ||||
|                 i += 1 | ||||
|             curr += xs[i] | ||||
|             result.append(curr) | ||||
|             i += 1 | ||||
|         # integers | ||||
|         elif xs[i] in "0123456789": | ||||
|             curr = xs[i] | ||||
|             i += 1 | ||||
|             while xs[i] in "0123456789": | ||||
|                 curr += xs[i] | ||||
|                 i += 1 | ||||
|             result.append(int(curr)) | ||||
|         # whitespace | ||||
|         elif xs[i] in {" ", "\n"}: | ||||
|             i += 1 | ||||
|     return result | ||||
| 
 | ||||
| def parse_json(x): | ||||
|     """ | ||||
|     Attempt to parse the string, `x`, into JSON. | ||||
|     """ | ||||
|     tokens = tokenize(x) | ||||
|     return parse_object(Parser(tokens)) | ||||
| 
 | ||||
| def parse_object(parser): | ||||
|     if parser.match(['{']): | ||||
|         key = parse_string(parser) | ||||
|         parser.expect([':']) | ||||
|         value = parse_object(parser) | ||||
|         result = [(key, value)] | ||||
|         while parser.match([',']): | ||||
|             key = parse_string(parser) | ||||
|             parser.match([':']) | ||||
|             value = parse_object(parser) | ||||
|             result.append((key, value)) | ||||
|         return result | ||||
|     return parse_array(parser) | ||||
| 
 | ||||
| def parse_array(parser): | ||||
|     if parser.match(['[']): | ||||
|         if parser.match([']']): | ||||
|             return [] | ||||
|         result = [parse_object(parser)] | ||||
|         while parser.match([',']): | ||||
|             result.append(parse_object(parser)) | ||||
|         parser.expect([']']) | ||||
|         return result | ||||
|     else: | ||||
|         return parse_literal(parser) | ||||
| 
 | ||||
| def parse_string(parser): | ||||
|     if parser.curr().startswith("\""): | ||||
|         return parser.consume() | ||||
|     else: | ||||
|         raise Exception("Unexpected token: {}".format(parser.curr())) | ||||
| 
 | ||||
| def parse_literal(parser): | ||||
|     return parser.consume() | ||||
| 
 | ||||
| sample = """ | ||||
| { | ||||
|   "glossary": { | ||||
|     "title": "example glossary", | ||||
|     "GlossDiv": { | ||||
|       "title": "S", | ||||
|       "GlossList": { | ||||
|         "GlossEntry": { | ||||
|           "ID": "SGML", | ||||
|           "SortAs": "SGML", | ||||
|           "GlossTerm": "Standard Generalized Markup Language", | ||||
|           "Acronym": "SGML", | ||||
|           "Abbrev": "ISO 8879:1986", | ||||
|           "GlossDef": { | ||||
|             "para": "A meta-markup language, used to create markup languages such as DocBook.", | ||||
|             "GlossSeeAlso": [ | ||||
|               "GML", | ||||
|               "XML" | ||||
|             ] | ||||
|           }, | ||||
|           "GlossSee": "markup" | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| """ | ||||
| 
 | ||||
| print(parse_json(sample)) | ||||
							
								
								
									
										28
									
								
								scratch/facebook/parsing/parser.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								scratch/facebook/parsing/parser.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| class Parser(object): | ||||
|     def __init__(self, tokens): | ||||
|         self.tokens = tokens | ||||
|         self.i = 0 | ||||
| 
 | ||||
|     def prev(self): | ||||
|         return self.tokens[self.i - 1] | ||||
| 
 | ||||
|     def curr(self): | ||||
|         return self.tokens[self.i] | ||||
| 
 | ||||
|     def consume(self): | ||||
|         if not self.exhausted(): | ||||
|             self.i += 1 | ||||
|             return self.prev() | ||||
| 
 | ||||
|     def match(self, xs): | ||||
|         if not self.exhausted() and self.curr() in xs: | ||||
|             self.consume() | ||||
|             return True | ||||
|         return False | ||||
| 
 | ||||
|     def expect(self, xs): | ||||
|         if not self.match(xs): | ||||
|             raise Exception("Expected token \"{}\" but received \"{}\"".format(xs, self.curr())) | ||||
| 
 | ||||
|     def exhausted(self): | ||||
|         return self.i >= len(self.tokens) | ||||
							
								
								
									
										174
									
								
								scratch/facebook/parsing/regex.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								scratch/facebook/parsing/regex.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,174 @@ | |||
| # Writing a small proof-of-concept... | ||||
| #   - lexer | ||||
| #   - parser | ||||
| #   - compiler | ||||
| # ...for regex. | ||||
| 
 | ||||
| from parser import Parser | ||||
| import string | ||||
| 
 | ||||
| ################################################################################ | ||||
| # Top-Level API | ||||
| ################################################################################ | ||||
| 
 | ||||
| def tokenize(xs): | ||||
|     """ | ||||
|     Transform `xs` into a list of tokens. | ||||
| 
 | ||||
|     Also: expand shorthand symbols using the following table: | ||||
|       - ? -> {0,1} | ||||
|       - * -> {0,} | ||||
|       - + -> {1,} | ||||
|     """ | ||||
|     result = [] | ||||
|     i = 0 | ||||
|     shorthand = { | ||||
|         "?": ["{", 0, ",", 1, "}"], | ||||
|         "*": ["{", 0, ",", "}"], | ||||
|         "+": ["{", 1, ",", "}"], | ||||
|     } | ||||
|     while i < len(xs): | ||||
|         if xs[i] in shorthand: | ||||
|             for c in shorthand[xs[i]]: | ||||
|                 result.append(c) | ||||
|             i += 1 | ||||
|         elif xs[i] == "{": | ||||
|             result.append(xs[i]) | ||||
|             i += 1 | ||||
|             curr = "" | ||||
|             while xs[i] in string.digits: | ||||
|                 curr += xs[i] | ||||
|                 i += 1 | ||||
|             result.append(int(curr)) | ||||
|             assert xs[i] == "," | ||||
|             result.append(",") | ||||
|             i += 1 | ||||
|             curr = "" | ||||
|             while xs[i] in string.digits: | ||||
|                 curr += xs[i] | ||||
|                 i += 1 | ||||
|             result.append(int(curr)) | ||||
|         else: | ||||
|             result.append(xs[i]) | ||||
|             i += 1 | ||||
|     return result | ||||
| 
 | ||||
| def parse(expr): | ||||
|     """ | ||||
|     Tokenize `expr` and convert it into a parse-tree. | ||||
|     """ | ||||
|     tokens = tokenize(expr) | ||||
|     return parse_tokens(tokens) | ||||
| 
 | ||||
| def compile(xs): | ||||
|     """ | ||||
|     Transform `xs`, a parse-tree representing a regex, into a function that | ||||
|     accepts a string, and returns the substring that the regex matches. | ||||
|     """ | ||||
|     def fn(input): | ||||
|         match = "" | ||||
|         i = 0 | ||||
|         for x in xs: | ||||
|             matches, q = x[1], x[2] | ||||
|             lo, hi = q[1], q[2] | ||||
|             for j in range(lo): | ||||
|                 if i < len(input) and input[i] in matches: | ||||
|                     match += input[i] | ||||
|                     i += 1 | ||||
|                 else: | ||||
|                     print("Failed to match {} with {}".format(input[i], matches)) | ||||
|                     return None | ||||
|             if hi == float('inf'): | ||||
|                 while i < len(input) and input[i] in matches: | ||||
|                     match += input[i] | ||||
|                     i += 1 | ||||
|             else: | ||||
|                 for j in range(hi - lo): | ||||
|                     if i < len(input) and input[i] in matches: | ||||
|                         match += input[i] | ||||
|                         i += 1 | ||||
|         return match | ||||
|     return fn | ||||
| 
 | ||||
| ################################################################################ | ||||
| # Helper Functions | ||||
| ################################################################################ | ||||
| 
 | ||||
| def parse_tokens(tokens): | ||||
|     result = [] | ||||
|     parser = Parser(tokens) | ||||
|     while not parser.exhausted(): | ||||
|         result.append(parse_expression(parser)) | ||||
|     return result | ||||
| 
 | ||||
| def parse_expression(parser): | ||||
|     if parser.curr() == "[": | ||||
|         return parse_character_class(parser) | ||||
|     else: | ||||
|         return parse_character(parser) | ||||
| 
 | ||||
| def parse_character_class(parser): | ||||
|     parser.expect("[") | ||||
|     beg = parser.consume() | ||||
|     parser.expect("-") | ||||
|     end = parser.consume() | ||||
|     parser.expect("]") | ||||
|     if parser.curr() == "{": | ||||
|         q = parse_quantifier(parser) | ||||
|     return char_class(xs=expand_range(beg, end), q=q) | ||||
| 
 | ||||
| def parse_quantifier(parser): | ||||
|     parser.expect("{") | ||||
|     if parser.match([","]): | ||||
|         end = parser.consume() | ||||
|         parser.expect("}") | ||||
|         return quantifier(beg=0, end=end) | ||||
|     else: | ||||
|         beg = parser.consume() | ||||
|         parser.expect(",") | ||||
|         if parser.match(["}"]): | ||||
|             return quantifier(beg=beg) | ||||
|         else: | ||||
|             end = parser.consume() | ||||
|             parser.expect("}") | ||||
|             return quantifier(beg=beg, end=end) | ||||
| 
 | ||||
| def parse_character(parser): | ||||
|     c = parser.consume() | ||||
|     q = None | ||||
|     if parser.curr() == "{": | ||||
|         q = parse_quantifier(parser) | ||||
|     return char_class(xs={c}, q=q) | ||||
| 
 | ||||
| def char_class(xs=set(), q=None): | ||||
|     if not q: | ||||
|         q = quantifier(beg=1, end=1) | ||||
|     return ["CHARACTER_CLASS", xs, q] | ||||
| 
 | ||||
| def expand_range(beg, end): | ||||
|     # TODO: Implement this | ||||
|     return {string.printable[i] | ||||
|             for i in range(string.printable.index(beg), | ||||
|                            string.printable.index(end) + 1)} | ||||
| 
 | ||||
| def quantifier(beg=0, end=float('inf')): | ||||
|     return ['QUANTIFIER', beg, end] | ||||
| 
 | ||||
| ################################################################################ | ||||
| # Tests | ||||
| ################################################################################ | ||||
| 
 | ||||
| xs = [ | ||||
|     ("[a-c]*[0-9]{2,3}", ["dog"]), | ||||
|     ("ca+t?", ["cat", "caaaat", "ca", "dog"]), | ||||
| ] | ||||
| 
 | ||||
| for re, inputs in xs: | ||||
|     print("Regex:  {}".format(re)) | ||||
|     print("Tokens: {}".format(tokenize(re))) | ||||
|     print("Parsed: {}".format(parse(re))) | ||||
|     print("\nTESTS") | ||||
|     for input in inputs: | ||||
|         print("Attempting to match \"{}\"...".format(input)) | ||||
|         parser = compile(parse(re)) | ||||
|         print("Result: \"{}\"\n".format(parser(input))) | ||||
							
								
								
									
										17
									
								
								scratch/facebook/permutation-palindrome.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								scratch/facebook/permutation-palindrome.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| from collections import Counter | ||||
| 
 | ||||
| def is_palindrome(x): | ||||
|     return len([count for _, count in Counter(x).items() if count % 2 == 1]) <= 1 | ||||
| 
 | ||||
| 
 | ||||
| xs = [("civic", True), | ||||
|       ("ivicc", True), | ||||
|       ("civil", False), | ||||
|       ("livci", False)] | ||||
| 
 | ||||
| for x, expected in xs: | ||||
|     result = is_palindrome(x) | ||||
|     print(x) | ||||
|     print(result) | ||||
|     assert result == expected | ||||
|     print("Success!") | ||||
							
								
								
									
										33
									
								
								scratch/facebook/product-of-all-other-numbers.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								scratch/facebook/product-of-all-other-numbers.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | |||
| from random import randint | ||||
| from math import floor | ||||
| 
 | ||||
| # loop {forwards, backwards, up, down} | ||||
| # through a table of values, [[a]]. | ||||
| 
 | ||||
| def product(xs): | ||||
|     n = len(xs) | ||||
|     lhs = [1] * (n + 1) | ||||
|     for i in range(1, n): | ||||
|         lhs[i] = lhs[i - 1] * xs[i - 1] | ||||
|     rhs = [1] * (n + 1) | ||||
|     for i in range(n - 1, 0, -1): | ||||
|         rhs[i] = rhs[i + 1] * xs[i] | ||||
|     result = [] | ||||
|     for i in range(n): | ||||
|         result.append(lhs[i] * rhs[i + 1]) | ||||
|     return result | ||||
| 
 | ||||
| def computed_expected(xs): | ||||
|     product = 1 | ||||
|     for x in xs: | ||||
|         product *= x | ||||
|     return [floor(product / x) for x in xs] | ||||
| 
 | ||||
| xs = [randint(1, 10) for _ in range(5)] | ||||
| expected = computed_expected(xs) | ||||
| result = product(xs) | ||||
| print(xs, result, expected) | ||||
| assert result == expected | ||||
| print("Success!") | ||||
| 
 | ||||
| print(product([2, 4, 3, 10, 5])) | ||||
							
								
								
									
										20
									
								
								scratch/facebook/queue-two-stacks.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								scratch/facebook/queue-two-stacks.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| from stack import Stack | ||||
| 
 | ||||
| class Queue(object): | ||||
|     def __init__(self): | ||||
|         self.lhs = Stack() | ||||
|         self.rhs = Stack() | ||||
| 
 | ||||
|     def enqueue(self, x): | ||||
|         self.rhs.push(x) | ||||
| 
 | ||||
|     def dequeue(self, x): | ||||
|         y = self.rhs.pop() | ||||
|         while y: | ||||
|             self.lhs.push(y) | ||||
|             y = self.rhs.pop() | ||||
|         result = self.lhs.pop() | ||||
|         y = self.lhs.pop() | ||||
|         while y: | ||||
|             self.rhs.push(y) | ||||
|         return result | ||||
|  | @ -0,0 +1,33 @@ | |||
| from math import floor | ||||
| 
 | ||||
| def find_magic_index_brute(xs): | ||||
|     for i in range(len(xs)): | ||||
|         if xs[i] == i: | ||||
|             return i | ||||
|     return -1 | ||||
| 
 | ||||
| def mid(lo, hi): | ||||
|     return lo + floor((hi - lo) / 2) | ||||
| 
 | ||||
| def find_magic_index(xs): | ||||
|     lo, hi = 0, len(xs) - 1 | ||||
|     return do_find_magic_index(xs, 0, len(xs) - 1) | ||||
| 
 | ||||
| def do_find_magic_index(xs, lo, hi): | ||||
|     pass | ||||
| 
 | ||||
| xss = [ | ||||
|     [], | ||||
|     [-1,0,2,4,5,6], | ||||
|     [1,1,1,1,1,5], | ||||
|     [-2,-2,-2,-2,4], | ||||
|     [1,2,3,4,5], | ||||
| ] | ||||
| 
 | ||||
| for xs in xss: | ||||
|     print(xs) | ||||
|     a = find_magic_index_brute(xs) | ||||
|     b = find_magic_index(xs) | ||||
|     print(a, b) | ||||
|     assert a == b | ||||
|     print("Success!") | ||||
|  | @ -0,0 +1,56 @@ | |||
| # Given an infinite supply of: | ||||
| #   - quarters | ||||
| #   - dimes | ||||
| #   - nickels | ||||
| #   - pennies | ||||
| # Write a function to count the number of ways to make change of n. | ||||
| 
 | ||||
| def get(table, row, col): | ||||
|     """ | ||||
|     Defensively get cell `row`, `col` from `table`. | ||||
|     """ | ||||
|     if row < 0 or row >= len(table): | ||||
|         return 0 | ||||
|     if col < 0 or col >= len(table[0]): | ||||
|         return 0 | ||||
|     return table[row][col] | ||||
| 
 | ||||
| def print_table(table): | ||||
|     print('\n'.join([ | ||||
|         ','.join([str(col) for col in table[row]]) | ||||
|         for row in range(len(table))])) | ||||
| 
 | ||||
| def init_table(rows=0, cols=0, default=0): | ||||
|     result = [] | ||||
|     for row in range(rows): | ||||
|         r = [] | ||||
|         for col in range(cols): | ||||
|             r.append(default) | ||||
|         result.append(r) | ||||
|     return result | ||||
| 
 | ||||
| def make_change(n): | ||||
|     coins = [1, 5, 10, 25] | ||||
|     table = init_table(rows=len(coins), cols=n) | ||||
| 
 | ||||
|     for row in range(len(table)): | ||||
|         for col in range(len(table[row])): | ||||
|             curr_coin = coins[row] | ||||
|             curr_n = col + 1 | ||||
|             # a | ||||
|             a = get(table, row - 1, col) | ||||
|             # b | ||||
|             b = get(table, row, curr_n - curr_coin - 1) | ||||
|             # c | ||||
|             c = 1 if curr_coin <= curr_n else 0 | ||||
|             # commit | ||||
|             if curr_coin == curr_n: | ||||
|                 table[row][col] = a + c | ||||
|             else: | ||||
|                 table[row][col] = a + b * c | ||||
|             # debug | ||||
|             print_table(table) | ||||
|             print() | ||||
|     return table[-1][-1] | ||||
| 
 | ||||
| print(make_change(7)) | ||||
|  | @ -0,0 +1,36 @@ | |||
| from collection import deque | ||||
| 
 | ||||
| def fill(point, canvas, color): | ||||
|     if x not in canvas: | ||||
|         return | ||||
|     elif y not in canvas[x]: | ||||
|         return | ||||
| 
 | ||||
|     x, y = point | ||||
|     if canvas[y][x] == color: | ||||
|         return | ||||
|     canvas[y][x] = color | ||||
|     fill((x + 1, y), canvas, color) | ||||
|     fill((x - 1, y), canvas, color) | ||||
|     fill((x, y + 1), canvas, color) | ||||
|     fill((x, y - 1), canvas, color) | ||||
| 
 | ||||
| def fill_bfs(point, canvas, color): | ||||
|     x, y = point | ||||
|     if x not in canvas: | ||||
|         return None | ||||
|     if y not in canvas[x]: | ||||
|         return None | ||||
|     xs = deque() | ||||
|     xs.append((x, y)) | ||||
|     while xs: | ||||
|         x, y = xs.popleft() | ||||
|         canvas[y][x] = color | ||||
|         for x2, y2 in [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)]: | ||||
|             if x2 not in canvas: | ||||
|                 continue | ||||
|             elif y2 not in canvas[x2]: | ||||
|                 continue | ||||
|             if canvas[y2][x2] != color: | ||||
|                 xs.append((x2, y2)) | ||||
|     return None | ||||
|  | @ -0,0 +1,114 @@ | |||
| # BNF | ||||
| # expression -> bool ( ( '|' | '&' | '^' ) bool )* | ||||
| # bool       -> '0' | '1' | ||||
| 
 | ||||
| def tokenize(xs): | ||||
|     result = [] | ||||
|     for c in xs: | ||||
|         if c == '0': | ||||
|             result.append(0) | ||||
|         elif c == '1': | ||||
|             result.append(1) | ||||
|         elif c in "&|^": | ||||
|             result.append(c) | ||||
|         else: | ||||
|             raise Exception("Unexpected token, \"{}\"".format(c)) | ||||
|     return result | ||||
| 
 | ||||
| class Parser(object): | ||||
|     def __init__(self, tokens): | ||||
|         self.tokens = tokens | ||||
|         self.i = 0 | ||||
| 
 | ||||
|     def prev(self): | ||||
|         return self.tokens[self.i - 1] | ||||
| 
 | ||||
|     def curr(self): | ||||
|         return self.tokens[self.i] | ||||
| 
 | ||||
|     def match(self, xs): | ||||
|         if self.exhausted(): | ||||
|             return False | ||||
|         if (self.curr() in xs): | ||||
|             self.consume() | ||||
|             return True | ||||
|         return False | ||||
| 
 | ||||
|     def consume(self): | ||||
|         result = self.curr() | ||||
|         self.i += 1 | ||||
|         return result | ||||
| 
 | ||||
|     def exhausted(self): | ||||
|         return self.i >= len(self.tokens) | ||||
| 
 | ||||
| def recursive_descent(tokens): | ||||
|     parser = Parser(tokens) | ||||
|     return parse_expression(parser) | ||||
| 
 | ||||
| def parse_expression(parser): | ||||
|     lhs = parse_bool(parser) | ||||
|     while parser.match(['|', '&', '^']): | ||||
|         op = parser.prev() | ||||
|         rhs = parse_expression(parser) | ||||
|         lhs = [op, lhs, rhs] | ||||
|     return lhs | ||||
| 
 | ||||
| def parse_bool(parser): | ||||
|     if parser.curr() == 0: | ||||
|         parser.consume() | ||||
|         return False | ||||
|     elif parser.curr() == 1: | ||||
|         parser.consume() | ||||
|         return True | ||||
|     else: | ||||
|         raise Exception("Unexpected token: {}".format(parser.curr())) | ||||
| 
 | ||||
| def f(expr, result): | ||||
|     tokens = tokenize(expr) | ||||
|     tree = recursive_descent(tokens) | ||||
|     return do_f(tree, result) | ||||
| 
 | ||||
| def do_f(tree, result): | ||||
|     if type(tree) == bool: | ||||
|         if tree == result: | ||||
|             return 1 | ||||
|         else: | ||||
|             return 0 | ||||
| 
 | ||||
|     op, lhs, rhs = tree[0], tree[1], tree[2] | ||||
|     truth_tables = { | ||||
|         True: { | ||||
|             '|': [ | ||||
|                 (True, True), | ||||
|                 (True, False), | ||||
|                 (False, True), | ||||
|             ], | ||||
|             '&': [ | ||||
|                 (True, True), | ||||
|             ], | ||||
|             '^': [ | ||||
|                 (True, False), | ||||
|                 (False, True), | ||||
|             ], | ||||
|         }, | ||||
|         False: { | ||||
|             '|': [ | ||||
|                 (False, False), | ||||
|             ], | ||||
|             '&': [ | ||||
|                 (False, False), | ||||
|                 (True, False), | ||||
|                 (False, True), | ||||
|             ], | ||||
|             '^': [ | ||||
|                 (True, True), | ||||
|                 (False, False), | ||||
|             ], | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return sum([do_f(lhs, x) * do_f(rhs, y) for x, y in truth_tables[result][op]]) | ||||
| 
 | ||||
| print(f("1^0|0|1", False)) | ||||
| print(f("1|0|1|1", False)) | ||||
|  | @ -0,0 +1,13 @@ | |||
| def char_and_rest(i, xs): | ||||
|     return xs[i], xs[:i] + xs[i+1:] | ||||
| 
 | ||||
| # perms :: String -> [String] | ||||
| def perms(xs): | ||||
|     if len(xs) == 1: | ||||
|         return [xs] | ||||
|     result = [] | ||||
|     for c, rest in [char_and_rest(i, xs) for i in range(len(xs))]: | ||||
|         result += [c + perm for perm in perms(rest)] | ||||
|     return result | ||||
| 
 | ||||
| print(perms("cat")) | ||||
|  | @ -0,0 +1,28 @@ | |||
| import random | ||||
| 
 | ||||
| def factorial(n): | ||||
|     result = 1 | ||||
|     for i in range(1, n + 1): | ||||
|         result *= i | ||||
|     return result | ||||
| 
 | ||||
| def travel(a, b): | ||||
|     if a == b: | ||||
|         return 1 | ||||
| 
 | ||||
|     ax, ay = a | ||||
|     bx, by = b | ||||
|     if ax > bx or ay > by: | ||||
|         return 0 | ||||
| 
 | ||||
|     return sum([travel((ax + 1, ay), b), travel((ax, ay + 1), b)]) | ||||
| 
 | ||||
| def travel_compute(a, b): | ||||
|     bx, by = b | ||||
|     return int(factorial(bx + by) / (factorial(bx) * factorial(by))) | ||||
| 
 | ||||
| a = (0, 0) | ||||
| b = (random.randint(1, 10), random.randint(1, 10)) | ||||
| print("Travelling to {}, {}".format(b[0], b[1])) | ||||
| print(travel(a, b)) | ||||
| print(travel_compute(a, b)) | ||||
|  | @ -0,0 +1 @@ | |||
| # accidentally deleted my solution... TBI (again) | ||||
|  | @ -0,0 +1,41 @@ | |||
| # take-aways: | ||||
| #   - Use integers as lists of boolean values | ||||
| #   - Use 1 << n to compute 2^n where n = len(xs) | ||||
| 
 | ||||
| def set_from_int(xs, n): | ||||
|     result = [] | ||||
|     for i in range(len(xs)): | ||||
|         if n & (1 << i) != 0: | ||||
|             result.append(xs[i]) | ||||
|     return result | ||||
| 
 | ||||
| # subsets :: Set a -> List (Set a) | ||||
| def subsets(xs): | ||||
|     n = len(xs) | ||||
|     return [set_from_int(xs, i) for i in range(1 << n)] | ||||
| 
 | ||||
| #   0 1 2 | ||||
| # 0 N Y Y | ||||
| # 1 _ N Y | ||||
| # 2 _ _ N | ||||
| 
 | ||||
| # For my interview, be able to compute *permutations* and *combinations* | ||||
| 
 | ||||
| # This differs from permutations because this is about finding combinations... | ||||
| # | ||||
| # bottom-up | ||||
| # 0 =>        { } | ||||
| # 1 =>  {3}   {4}   {3} | ||||
| # 2 => {5,4} {5,3} {4,3} | ||||
| 
 | ||||
| xs = [ | ||||
|     ([], [[]]), | ||||
|     ([5], [[], [5]]), | ||||
|     ([5,4], [[],[5],[4],[5,4]]), | ||||
| ] | ||||
| 
 | ||||
| for x, expected in xs: | ||||
|     result = subsets(x) | ||||
|     print("subsets({}) => {} == {}".format(x, result, expected)) | ||||
|     assert result == expected | ||||
|     print("Success!") | ||||
|  | @ -0,0 +1,50 @@ | |||
| def valid_parens(n): | ||||
|     if n == 0: | ||||
|         return [] | ||||
|     if n == 1: | ||||
|         return ["()"] | ||||
| 
 | ||||
|     result = set() | ||||
|     for x in valid_parens(n - 1): | ||||
|         result.add("({})".format(x)) | ||||
|         result.add("(){}".format(x)) | ||||
|         result.add("{}()".format(x)) | ||||
|     return result | ||||
| 
 | ||||
| def valid_parens_efficient(n): | ||||
|     result = [] | ||||
|     curr = [''] * n**2 | ||||
|     do_valid_parens_efficient(result, curr, 0, n, n) | ||||
|     return result | ||||
| 
 | ||||
| def do_valid_parens_efficient(result, curr, i, lhs, rhs): | ||||
|     if lhs == 0 and rhs == 0: | ||||
|         result.append(''.join(curr)) | ||||
|     else: | ||||
|         if lhs > 0: | ||||
|             curr[i] = '(' | ||||
|             do_valid_parens_efficient(result, curr, i + 1, lhs - 1, rhs) | ||||
|         if rhs > lhs: | ||||
|             curr[i] = ')' | ||||
|             do_valid_parens_efficient(result, curr, i + 1, lhs, rhs - 1) | ||||
| 
 | ||||
| # Avoids recursion by using either a stack or a queue. I think this version is | ||||
| # easier to understand. | ||||
| def valid_parens_efficient_2(n): | ||||
|     result = [] | ||||
|     xs = [] | ||||
|     xs.append(('', n, n)) | ||||
|     while xs: | ||||
|         curr, lhs, rhs = xs.pop() | ||||
|         print(curr) | ||||
|         if lhs == 0 and rhs == 0: | ||||
|             result.append(''.join(curr)) | ||||
|         if lhs > 0: | ||||
|             xs.append((curr + '(', lhs - 1, rhs)) | ||||
|         if rhs > lhs: | ||||
|             xs.append((curr + ')', lhs, rhs - 1)) | ||||
|     return result | ||||
| 
 | ||||
| # print(valid_parens(4)) | ||||
| print(valid_parens_efficient(3)) | ||||
| print(valid_parens_efficient_2(3)) | ||||
							
								
								
									
										19
									
								
								scratch/facebook/recursive-string-permutations.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								scratch/facebook/recursive-string-permutations.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | |||
| # permutations: no repeat characters | ||||
| 
 | ||||
| def char_and_rest(i, xs): | ||||
|     return xs[i], xs[0:i] + xs[i + 1:] | ||||
| 
 | ||||
| def permutations(xs): | ||||
|     if len(xs) == 1: | ||||
|         return [xs] | ||||
|     result = [] | ||||
|     for c, rest in [char_and_rest(i, xs) for i in range(len(xs))]: | ||||
|         result += [c + perm for perm in permutations(rest)] | ||||
|     return result | ||||
| 
 | ||||
| expected = ["cat", "cta", "act", "atc", "tca", "tac"] | ||||
| result = permutations("cat") | ||||
| print(result, expected) | ||||
| assert len(result) == len(expected) | ||||
| assert result == expected | ||||
| print("Success!") | ||||
							
								
								
									
										25
									
								
								scratch/facebook/reverse-linked-list.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								scratch/facebook/reverse-linked-list.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| from linked_list import Node | ||||
| 
 | ||||
| def reverse(node): | ||||
|     prev, curr, next = None, node, node.next | ||||
| 
 | ||||
|     while curr: | ||||
|         curr.next = prev | ||||
|         prev = curr | ||||
|         curr = next | ||||
|         next = curr.next if curr else None | ||||
|     return prev | ||||
| 
 | ||||
| one = Node(1) | ||||
| two = Node(2) | ||||
| three = Node(3) | ||||
| one.next = two | ||||
| two.next = three | ||||
| 
 | ||||
| print(one) | ||||
| result = reverse(one) | ||||
| print(result) | ||||
| assert all([result == three, | ||||
|             three.next == two, | ||||
|             two.next == one]) | ||||
| print("Success!") | ||||
							
								
								
									
										14
									
								
								scratch/facebook/reverse-string-in-place.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								scratch/facebook/reverse-string-in-place.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| # reverse :: [Char] -> () | ||||
| def reverse(xs): | ||||
|     i = 0 | ||||
|     j = len(xs) - 1 | ||||
|     while i < j: | ||||
|         xs[i], xs[j] = xs[j], xs[i] | ||||
|         i += 1 | ||||
|         j -= 1 | ||||
| 
 | ||||
| xs = [list("testing"), list("a"), list("to")] | ||||
| for x in xs: | ||||
|     print(x) | ||||
|     reverse(x) | ||||
|     print(x) | ||||
							
								
								
									
										8
									
								
								scratch/facebook/reverse-words.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								scratch/facebook/reverse-words.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| # reverse_word :: [Char] -> () | ||||
| def reverse_words(x): | ||||
|     pass | ||||
| 
 | ||||
| x = list("This is a test") | ||||
| print(''.join(x)) | ||||
| reverse_words(x) | ||||
| print(''.join(result)) | ||||
							
								
								
									
										94
									
								
								scratch/facebook/scratch.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								scratch/facebook/scratch.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,94 @@ | |||
| # This is a scratch pad for randomly selected questions | ||||
| 
 | ||||
| # def char_and_rest(i, xs): | ||||
| #     return xs[i], xs[:i] + xs[i+1:] | ||||
| 
 | ||||
| # def perms(xs): | ||||
| #     if len(xs) == 1: | ||||
| #         return [xs] | ||||
| #     result = [] | ||||
| #     for i in range(len(xs)): | ||||
| #         c, rest = char_and_rest(i, xs) | ||||
| #         for perm in perms(rest): | ||||
| #             result.append(c + ''.join(perm)) | ||||
| #     return result | ||||
| 
 | ||||
| # print(perms(list("woah"))) | ||||
| 
 | ||||
| # def f(take_out, dine_in, served): | ||||
| #     j, k = 0, 0 | ||||
| #     for i in range(len(served)): | ||||
| #         if j < len(take_out) and served[i] == take_out[j]: | ||||
| #             j += 1 | ||||
| #         elif k < len(dine_in) and served[i] == dine_in[k]: | ||||
| #             k += 1 | ||||
| #         else: | ||||
| #             return False | ||||
| #     if j < len(take_out) or k < len(dine_in): | ||||
| #         return False | ||||
| #     return True | ||||
| 
 | ||||
| # take_out = [17, 8, 24] | ||||
| # dine_in = [12, 19, 2] | ||||
| # served = [17, 8, 12, 19, 24, 2] | ||||
| # print(f(take_out, dine_in, served)) | ||||
| 
 | ||||
| # def match(a, b): | ||||
| #     if a == '{': | ||||
| #         return b == '}' | ||||
| #     if a == '[': | ||||
| #         return b == ']' | ||||
| #     if a == '(': | ||||
| #         return b == ')' | ||||
| #     return False | ||||
| 
 | ||||
| # def f(xs): | ||||
| #     s = [] | ||||
| #     for c in xs: | ||||
| #         if c in {'{', '[', '('}: | ||||
| #             s.append(c) | ||||
| #         elif c in {'}', ']', ')'}: | ||||
| #             opener = s.pop() | ||||
| #             if not match(opener, c): | ||||
| #                 return False | ||||
| #     return len(s) == 0 | ||||
| 
 | ||||
| # assert f("{[]()}") | ||||
| # assert f("{[(])}") == False | ||||
| # assert f("{[}") == False | ||||
| # print("Success!") | ||||
| 
 | ||||
| # def valid_bst(node): | ||||
| #     lhs = max_bst_value(node.left) if node.left else float('-inf') | ||||
| #     rhs = min_bst_value(node.right) if node.right else float('inf') | ||||
| 
 | ||||
| #     return and([ | ||||
| #         lhs <= node.value, | ||||
| #         rhs > node.value, | ||||
| #         valid_bst(node.left), | ||||
| #         valid_bst(node.right), | ||||
| #     ]) | ||||
| 
 | ||||
| import random | ||||
| import math | ||||
| 
 | ||||
| def shuffle(xs): | ||||
|     n = len(xs) | ||||
|     for i in range(n - 1): | ||||
|         j = random.randint(i + 1, n - 1) | ||||
|         xs[i], xs[j] = xs[j], xs[i] | ||||
|     return xs | ||||
| 
 | ||||
| def as_card(i): | ||||
|     if i not in range(1, 53): | ||||
|         raise Exception("Not a card") | ||||
|     # 1 | ||||
|     suit = ['Hearts', 'Clubs', 'Diamonds', 'Spades'][math.floor((i - 1) / 13)] | ||||
|     n = ['Ace',2,3,4,5,6,7,8,9,10,'Jack','Queen','King'][(i - 1) % 13] | ||||
|     return '{} of {}'.format(n, suit) | ||||
| 
 | ||||
| xs = list(range(1, 53)) | ||||
| print(xs) | ||||
| shuffle(xs) | ||||
| for x in xs: | ||||
|     print(as_card(x)) | ||||
							
								
								
									
										22
									
								
								scratch/facebook/second-largest-item-in-bst.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								scratch/facebook/second-largest-item-in-bst.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| from collections import deque | ||||
| from node import Node, tree | ||||
| 
 | ||||
| def find_largest(node): | ||||
|     while node.right: | ||||
|         node = node.right | ||||
|     return node.value | ||||
| 
 | ||||
| def find_second_largest(node): | ||||
|     # parent of the rightmost, when rightmost is leaf | ||||
|     # max(rightmost.left) | ||||
|     prev = None | ||||
|     while node.right: | ||||
|         prev = node | ||||
|         node = node.right | ||||
|     if node.left: | ||||
|         return find_largest(node.left) | ||||
|     else: | ||||
|         return prev.value | ||||
| 
 | ||||
| assert find_second_largest(tree) == 72 | ||||
| print("Success!") | ||||
							
								
								
									
										17
									
								
								scratch/facebook/shuffle.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								scratch/facebook/shuffle.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| from random import randint | ||||
| 
 | ||||
| def get_random(i, j): | ||||
|     return randint(i, j) | ||||
| 
 | ||||
| def shuffle(xs): | ||||
|     for i in range(len(xs)): | ||||
|         j = get_random(i, len(xs) - 1) | ||||
|         xs[i], xs[j] = xs[j], xs[i] | ||||
| 
 | ||||
| xs = list(range(1, 53)) | ||||
| print(xs) | ||||
| assert len(set(xs)) == 52 | ||||
| shuffle(xs) | ||||
| assert len(set(xs)) == 52 | ||||
| print(xs) | ||||
| print("Success!") | ||||
							
								
								
									
										25
									
								
								scratch/facebook/stack.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								scratch/facebook/stack.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| class Stack(object): | ||||
|     def __init__(self): | ||||
|         self.items = [] | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         return self.items.__repr__() | ||||
| 
 | ||||
|     def push(self, x): | ||||
|         self.items.append(x) | ||||
| 
 | ||||
|     def pop(self): | ||||
|         if not self.items: | ||||
|             return None | ||||
|         return self.items.pop() | ||||
| 
 | ||||
|     def peek(self): | ||||
|         if not self.items: | ||||
|             return None | ||||
|         return self.items[-1] | ||||
| 
 | ||||
| def from_list(xs): | ||||
|     result = Stack() | ||||
|     for x in xs: | ||||
|         result.push(x) | ||||
|     return result | ||||
							
								
								
									
										16
									
								
								scratch/facebook/stock-price.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								scratch/facebook/stock-price.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| def max_profit(xs): | ||||
|     buy = xs[0] | ||||
|     profit = xs[1] - xs[0] | ||||
|     for price in xs[1:]: | ||||
|         profit = max(profit, price - buy) | ||||
|         buy = min(buy, price) | ||||
|     return profit | ||||
| 
 | ||||
| xs = [([10,7,5,8,11,9], 6), | ||||
|       ([10,8,7,6,5], -1)] | ||||
| 
 | ||||
| for x, expected in xs: | ||||
|     result = max_profit(x) | ||||
|     print(x, result) | ||||
|     assert result == expected | ||||
|     print("Success!") | ||||
							
								
								
									
										60
									
								
								scratch/facebook/todo.org
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								scratch/facebook/todo.org
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| * Array and string manipulation | ||||
| ** DONE Merging Meeting Times | ||||
| ** DONE Reverse String in Place | ||||
| ** TODO Reverse Words | ||||
| ** DONE Merge Sorted Arrays | ||||
| ** DONE Cafe Order Checker | ||||
| * Hashing and hash tables | ||||
| ** DONE Inflight Entertainment | ||||
| ** DONE Permutation Palindrome | ||||
| ** DONE Word Cloud Data | ||||
| ** DONE Top Scores | ||||
| * Greedy Algorithms | ||||
| ** DONE Apple Stocks | ||||
| ** DONE Highest Product of 3 | ||||
| ** DONE Product of All Other Numbers | ||||
| ** DONE Cafe Order Checker | ||||
| ** DONE In-Place Shuffle | ||||
| * Sorting, searching, and logarithms | ||||
| ** DONE Find Rotation Point | ||||
| ** TODO Find Repeat, Space Edition | ||||
| ** DONE Top Scores | ||||
| ** DONE Merging Meeting Times | ||||
| * Trees and graphs | ||||
| ** DONE Balanced Binary Tree | ||||
| ** DONE Binary Search Tree Checker | ||||
| ** DONE 2nd Largest Item in a Binary Search Tree | ||||
| ** DONE Graph Coloring | ||||
| ** DONE MeshMessage | ||||
| ** DONE Find Repeat, Space Edition BEAST MODE | ||||
| * Dynamic programming and recursion | ||||
| ** DONE Recursive String Permutations | ||||
| ** DONE Compute nth Fibonacci Number | ||||
| ** DONE Making Change | ||||
| ** DONE The Cake Thief | ||||
| ** DONE Balanced Binary Tree | ||||
| ** DONE Binary Search Tree Checker | ||||
| ** DONE 2nd Largest Item in a Binary Search Tree | ||||
| * Queues and stacks | ||||
| ** DONE Largest Stack | ||||
| ** DONE Implement A Queue With Two Stacks | ||||
| ** DONE Parenthesis Matching | ||||
| ** DONE Bracket Validator | ||||
| * Linked lists | ||||
| ** DONE Delete Node | ||||
| ** DONE Does This Linked List Have A Cycle? | ||||
| ** DONE Reverse A Linked List | ||||
| ** DONE Kth to Last Node in a Singly-Linked List | ||||
| ** DONE Find Repeat, Space Edition BEAST MODE | ||||
| * General programming | ||||
| ** TODO Rectangular Love | ||||
| ** TODO Temperature Tracker | ||||
| * Bit manipulation | ||||
| ** DONE The Stolen Breakfast Drone | ||||
| * Combinatorics, probability, and other math | ||||
| ** TODO Which Appears Twice | ||||
| ** TODO Find in Ordered Set | ||||
| ** TODO In-Place Shuffle | ||||
| ** TODO Simulate 5-sided die | ||||
| ** TODO Simulate 7-sided die | ||||
| ** TODO Two Egg Problem | ||||
							
								
								
									
										20
									
								
								scratch/facebook/top-scores.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								scratch/facebook/top-scores.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| import random | ||||
| from collections import deque | ||||
| 
 | ||||
| def sorted(xs): | ||||
|     result = [0] * 100 | ||||
|     for x in xs: | ||||
|         result[x - 1] += 1 | ||||
| 
 | ||||
|     answer = deque() | ||||
|     for i in range(len(result)): | ||||
|         x = result[i] | ||||
|         for _ in range(x): | ||||
|             answer.appendleft(i + 1) | ||||
| 
 | ||||
|     return list(answer) | ||||
| 
 | ||||
| scores = [random.choice(range(70, 100)) for _ in range(20)] | ||||
| print(scores) | ||||
| result = sorted(scores) | ||||
| print(result) | ||||
							
								
								
									
										61
									
								
								scratch/facebook/topo-sort.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								scratch/facebook/topo-sort.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,61 @@ | |||
| import random | ||||
| from heapq import heappush, heappop | ||||
| from collections import deque | ||||
| 
 | ||||
| # A topological sort returns the vertices of a graph sorted in an ascending | ||||
| # order by the number of incoming edges each vertex has. | ||||
| # | ||||
| # A few algorithms for solving this exist, and at the time of this writing, I | ||||
| # know none. I'm going to focus on two: | ||||
| #   1. Kahn's | ||||
| #   2. DFS (TODO) | ||||
| 
 | ||||
| def count_in_edges(graph): | ||||
|     result = {k: 0 for k in graph.keys()} | ||||
|     for xs in graph.values(): | ||||
|         for x in xs: | ||||
|             result[x] += 1 | ||||
|     return result | ||||
| 
 | ||||
| # Kahn's algorithm for returning a topological sorting of the vertices in | ||||
| # `graph`. | ||||
| def kahns_sort(graph): | ||||
|     result = [] | ||||
|     q = deque() | ||||
|     in_edges = count_in_edges(graph) | ||||
|     for x in [k for k, v in in_edges.items() if v == 0]: | ||||
|         q.append(x) | ||||
|     while q: | ||||
|         x = q.popleft() | ||||
|         result.append(x) | ||||
|         for c in graph[x]: | ||||
|             in_edges[c] -= 1 | ||||
|             if in_edges[c] == 0: | ||||
|                 q.append(c) | ||||
|     return result | ||||
| 
 | ||||
| graphs = [ | ||||
|     { | ||||
|         0: [], | ||||
|         1: [], | ||||
|         2: [3], | ||||
|         3: [1], | ||||
|         4: [0, 1], | ||||
|         5: [0, 2], | ||||
|     }, | ||||
|     { | ||||
|         'A': ['C', 'D'], | ||||
|         'B': ['D', 'E'], | ||||
|         'C': [], | ||||
|         'D': ['F', 'G'], | ||||
|         'E': [], | ||||
|         'F': [], | ||||
|         'G': ['I'], | ||||
|         'H': ['I'], | ||||
|         'I': [], | ||||
|     } | ||||
| ] | ||||
| 
 | ||||
| print("--- Kahn's --- ") | ||||
| for graph in graphs: | ||||
|     print(kahns_sort(graph)) | ||||
							
								
								
									
										100
									
								
								scratch/facebook/traversals.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								scratch/facebook/traversals.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,100 @@ | |||
| from math import floor | ||||
| 
 | ||||
| # Lists | ||||
| def cycle_backwards(times, xs): | ||||
|     n = len(xs) | ||||
|     for i in range(n * times): | ||||
|         print(xs[n - 1 - i % n]) | ||||
| 
 | ||||
| def cycle_forwards(times, xs): | ||||
|     n = len(xs) | ||||
|     for i in range(n * times): | ||||
|         print(xs[i % n]) | ||||
| 
 | ||||
| def backwards(xs): | ||||
|     n = len(xs) | ||||
|     for i in range(n): | ||||
|         print(xs[n - 1 - i]) | ||||
| 
 | ||||
| def forwards(xs): | ||||
|     for i in range(len(xs)): | ||||
|         print(xs[i]) | ||||
| 
 | ||||
| xs = [2, 5, 6, 9, 12] | ||||
| 
 | ||||
| print("Forwards") | ||||
| forwards(xs) | ||||
| print("Backwards") | ||||
| backwards(xs) | ||||
| print("Cycle forwards") | ||||
| cycle_forwards(2, xs) | ||||
| print("Cycle backwards") | ||||
| cycle_backwards(2, xs) | ||||
| 
 | ||||
| # Tables | ||||
| def tblr(table): | ||||
|     for row in range(len(table)): | ||||
|         for col in range(len(table[row])): | ||||
|             print(table[row][col]) | ||||
| 
 | ||||
| def tbrl(table): | ||||
|     for row in range(len(table)): | ||||
|         n = len(table[row]) | ||||
|         for col in range(n): | ||||
|             print(table[row][n - 1 - col]) | ||||
| 
 | ||||
| def btlr(table): | ||||
|     n = len(table) | ||||
|     for row in range(n): | ||||
|         for col in range(len(table[row])): | ||||
|             print(table[n - 1 - row][col]) | ||||
| 
 | ||||
| def btrl(table): | ||||
|     rows = len(table) | ||||
|     for row in range(rows): | ||||
|         cols = len(table[row]) | ||||
|         for col in range(cols): | ||||
|             print(table[rows - 1 - row][cols - 1 - col]) | ||||
| 
 | ||||
| def special(table): | ||||
|     rows = len(table) | ||||
|     cols = len(table[0]) | ||||
|     for col in range(cols): | ||||
|         for row in range(rows): | ||||
|             print(table[row][col]) | ||||
| 
 | ||||
| def double_bonus(table): | ||||
|     rows = len(table) | ||||
|     cols = len(table[0]) | ||||
|     for i in range(rows): | ||||
|         row = i | ||||
|         for col in range(cols): | ||||
|             print(table[row][col % cols]) | ||||
|             row = (row + 1) % rows | ||||
| 
 | ||||
| def free(table): | ||||
|     rows = len(table) | ||||
|     cols = len(table[0]) | ||||
|     d = rows * cols | ||||
|     for i in range(d): | ||||
|         row = floor((i % d) / cols) | ||||
|         col = i % cols | ||||
|         print(table[row][col]) | ||||
| 
 | ||||
| table = [[1,2,3,4], | ||||
|          [5,6,7,8]] | ||||
| 
 | ||||
| print("Top->Bottom, Left->Right") | ||||
| tblr(table) | ||||
| print("Top->Bottom, Right->Left") | ||||
| tbrl(table) | ||||
| print("Bottom->Top, Left->Right") | ||||
| btlr(table) | ||||
| print("Bottom->Top, Right->Left") | ||||
| btrl(table) | ||||
| print("Special") | ||||
| special(table) | ||||
| print("2x Bonus") | ||||
| double_bonus(table) | ||||
| print("Free") | ||||
| free(table) | ||||
							
								
								
									
										19
									
								
								scratch/facebook/utils.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								scratch/facebook/utils.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | |||
| def init_table(rows=0, cols=0, default=None): | ||||
|     table = [] | ||||
|     for row in range(rows): | ||||
|         x = [] | ||||
|         for col in range(cols): | ||||
|             x.append(default) | ||||
|         table.append(x) | ||||
|     return table | ||||
| 
 | ||||
| def get(table, row, col, default=0): | ||||
|     if row < 0 or col < 0: | ||||
|         return default | ||||
|     return table[row][col] | ||||
| 
 | ||||
| def print_table(table): | ||||
|     result = [] | ||||
|     for row in range(len(table)): | ||||
|         result.append(' '.join([str(cell) for cell in table[row]])) | ||||
|     print('\n'.join(result)) | ||||
							
								
								
									
										32
									
								
								scratch/facebook/word-cloud.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								scratch/facebook/word-cloud.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| def normalize(x): | ||||
|     noise = ".,;-" | ||||
|     for y in noise: | ||||
|         if x.endswith(y): | ||||
|             return normalize(x[0:-1]) | ||||
|         if x.startswith(y): | ||||
|             return normalize(x[1:]) | ||||
|     return x.lower() | ||||
| 
 | ||||
| def word_cloud(xs): | ||||
|     result = dict() | ||||
| 
 | ||||
|     for x in xs.split(' '): | ||||
|         k = normalize(x) | ||||
|         if k in result: | ||||
|             result[k] += 1 | ||||
|         else: | ||||
|             result[k] = 1 | ||||
| 
 | ||||
|     return result | ||||
| 
 | ||||
| result = word_cloud("This is just the beginning. The UK will lockdown again.") | ||||
| assert result.get('this') == 1 | ||||
| assert result.get('is') == 1 | ||||
| assert result.get('just') == 1 | ||||
| assert result.get('the') == 2 | ||||
| assert result.get('beginning') == 1 | ||||
| assert result.get('uk') == 1 | ||||
| assert result.get('will') == 1 | ||||
| assert result.get('lockdown') == 1 | ||||
| assert result.get('again') == 1 | ||||
| print("Success!") | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue