Tidy up structure of briefcase

I had a spare fifteen minutes and decided that I should tidy up my
monorepo. The work of tidying up is not finished; this is a small step in the
right direction.

TL;DR
- Created a tools directory
- Created a scratch directory (see README.md for more information)
- Added README.md to third_party
- Renamed delete_dotfile_symlinks -> symlinkManager
- Packaged symlinkManager as an executable symlink-mgr using buildGo
This commit is contained in:
William Carroll 2020-02-12 16:58:29 +00:00
parent 5ec5a6da8c
commit fabf1c9334
89 changed files with 53 additions and 41 deletions

6
scratch/README.md Normal file
View file

@ -0,0 +1,6 @@
# Scratch
The purpose of the `scratch` directory is to host practice exercises. Practice
encompasses things like working on data structures and algorithms problems for
upcoming coding interviews or general aptitude as well as writing code snippets
to help me learn a new programming language or understand an unfamiliar concept.

View file

@ -0,0 +1,40 @@
# Implementation for a problem from "Crack the Coding Interview".
#
# Dependencies:
# - python 2.7.16
# - entr 4.1
#
# To run the tests, run: `python 11_1.py`
# For a tight development loop, run: `echo 11_1.py | entr python /_`
#
# Author: William Carroll <wpcarro@gmail.com>
################################################################################
# Implementation
################################################################################
def insert_sorted(xs, ys):
"""
Merges `ys` into `xs` and ensures that the result is sorted.
Assumptions:
- `xs` and `ys` are both sorted.
- `xs` has enough unused space to accommodate each element in `ys`.
"""
for y in ys:
xi = xs.index(None) - 1
yi = xs.index(None)
xs[yi] = y
while xi != -1 and y < xs[xi]:
xs[xi], xs[yi] = xs[yi], xs[xi]
xi, yi = xi - 1, yi - 1
return xs
################################################################################
# Tests
################################################################################
assert insert_sorted([1, 3, 5, None, None], [2, 4]) == [1, 2, 3, 4, 5]
assert insert_sorted([None, None], [2, 4]) == [2, 4]
assert insert_sorted([None, None], [2, 4]) == [2, 4]
assert insert_sorted([1, 1, None, None], [0, 0]) == [0, 0, 1, 1]
assert insert_sorted([1, 1, None, None], [1, 1]) == [1, 1, 1, 1]
print('All tests pass!')

View file

@ -0,0 +1,11 @@
data Tree a = Node a [Tree a] deriving (Show)
withRoot :: [a] -> [Tree a]
withRoot xs = xs |> toThing |> fmap buildTree
buildTree :: (a, [a])
toTree :: [a] -> Tree a
toTree [x] = Node x []
toTree [x | xs] = Node x (toTree xs)

View file

@ -0,0 +1,87 @@
# This is practice for various types of list traversals that turn up.
xs = range(10)
n = len(xs)
print('---')
# pythonic left-to-right traversal
result = ''
for x in xs:
result += str(x)
print(result)
print('---')
# left-to-right traversal
result = ''
for i in range(n):
result += str(xs[i])
print(result)
print('---')
# right-to-left traversal
result = ''
for i in range(n):
result += str(xs[n - 1 - i])
print(result)
print('---')
# 2x left-to-right traversal
result = ''
for i in range(2 * n):
result += str(xs[i % n])
print(result)
print('---')
# 2x right-to-left traversal
result = ''
for i in range(2 * n):
result += str(xs[(n - 1 - i) % n])
print(result)
################################################################################
# Table traversals
################################################################################
table = [[row * 10 + i for i in range(10)] for row in range(3)]
row_ct = len(table)
col_ct = len(table[0])
print('---')
# 3x10 table traversal
result = ''
for row in table:
r = ''
for col in row:
r += '{:3d}'.format(col)
result += r + '\n'
print(result[0:-1])
print('---')
# 3x10 table traversal
result = ''
for row in range(row_ct):
r = ''
for col in range(col_ct):
r += '{:3d}'.format(table[row][col])
result += r + '\n'
print(result[0:-1])
print('---')
# 3x10 table traversal (reverse)
result = ''
for row in range(row_ct):
r = ''
for col in range(col_ct):
r += '{:3d}'.format(table[row_ct - 1 - row][col_ct - 1 - col])
result += r + '\n'
print(result)
print('---')
# 3x10 column-row traversal
result = ''
for col in range(col_ct):
r = ''
for row in range(row_ct):
r += '{:3d}'.format(table[row][col])
result += r + '\n'
print(result)

View file

@ -0,0 +1,145 @@
import unittest
from itertools import combinations
def balanced(xs):
"""Return True if `xs` contains no two values that differ by more than
one."""
if len(xs) == 0 or len(xs) == 1:
return True
if len(xs) == 2:
return math.abs(xs[0] - xs[1]) <= 1
else:
pass
def is_leaf(node):
return node.left is None and node.right is None
def is_balanced(tree_root):
"""Returns True if the difference between the depths of any two leaf nodes
does not exceed 1."""
depths = set()
populate_depths(tree_root, 0, depths)
# cartesian product - only the top half
for diff in set(abs(a - b) for a, b in combinations(depths, 2)):
if diff > 1:
return False
return True
def populate_depths(node, depth, depths):
if is_leaf(node):
depths.add(depth)
else:
if node.left is not None:
populate_depths(node.left, depth + 1, depths)
if node.right is not None:
populate_depths(node.right, depth + 1, depths)
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
class BinaryTreeNode(object):
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def insert_left(self, value):
self.left = Test.BinaryTreeNode(value)
return self.left
def insert_right(self, value):
self.right = Test.BinaryTreeNode(value)
return self.right
def test_full_tree(self):
tree = Test.BinaryTreeNode(5)
left = tree.insert_left(8)
right = tree.insert_right(6)
left.insert_left(1)
left.insert_right(2)
right.insert_left(3)
right.insert_right(4)
result = is_balanced(tree)
self.assertTrue(result)
def test_both_leaves_at_the_same_depth(self):
tree = Test.BinaryTreeNode(3)
left = tree.insert_left(4)
right = tree.insert_right(2)
left.insert_left(1)
right.insert_right(9)
result = is_balanced(tree)
self.assertTrue(result)
def test_leaf_heights_differ_by_one(self):
tree = Test.BinaryTreeNode(6)
left = tree.insert_left(1)
right = tree.insert_right(0)
right.insert_right(7)
result = is_balanced(tree)
self.assertTrue(result)
def test_leaf_heights_differ_by_two(self):
tree = Test.BinaryTreeNode(6)
left = tree.insert_left(1)
right = tree.insert_right(0)
right_right = right.insert_right(7)
right_right.insert_right(8)
result = is_balanced(tree)
self.assertFalse(result)
def test_three_leaves_total(self):
tree = Test.BinaryTreeNode(1)
left = tree.insert_left(5)
right = tree.insert_right(9)
right.insert_left(8)
right.insert_right(5)
result = is_balanced(tree)
self.assertTrue(result)
def test_both_subtrees_superbalanced(self):
tree = Test.BinaryTreeNode(1)
left = tree.insert_left(5)
right = tree.insert_right(9)
right_left = right.insert_left(8)
right.insert_right(5)
right_left.insert_left(7)
result = is_balanced(tree)
self.assertFalse(result)
def test_both_subtrees_superbalanced_two(self):
tree = Test.BinaryTreeNode(1)
left = tree.insert_left(2)
right = tree.insert_right(4)
left.insert_left(3)
left_right = left.insert_right(7)
left_right.insert_right(8)
right_right = right.insert_right(5)
right_right_right = right_right.insert_right(6)
right_right_right.insert_right(9)
result = is_balanced(tree)
self.assertFalse(result)
def test_only_one_node(self):
tree = Test.BinaryTreeNode(1)
result = is_balanced(tree)
self.assertTrue(result)
def test_linked_list_tree(self):
tree = Test.BinaryTreeNode(1)
right = tree.insert_right(2)
right_right = right.insert_right(3)
right_right.insert_right(4)
result = is_balanced(tree)
self.assertTrue(result)
unittest.main(verbosity=2)

View file

@ -0,0 +1,32 @@
def test(x, i):
return x & (1 << i) != 0
def set(x, i):
return x | (1 << i)
def clear(x, i):
return x & ~(1 << i)
def toggle(x, i):
if test(x, i):
return clear(x, i)
else:
return set(x, i)
def test_single(x):
if x == 0:
return False
else:
return x & (x - 1) == 0
print(test(0b1010, 3))
print('{0:b}'.format(set(0b1010, 1)))
print('{0:b}'.format(clear(0b1010, 1)))
print('{0:b}'.format(toggle(0b1010, 2)))
print(test_single(0b1010))
print(test_single(0b1000))

View file

@ -0,0 +1,63 @@
import unittest
################################################################################
# Solution
################################################################################
# is_valid :: String -> Boolean
def is_valid(xs):
s = []
seeking = {
'}': '{',
']': '[',
')': '(',
}
openers = seeking.values()
closers = seeking.keys()
for c in xs:
if c in openers:
s.append(c)
elif c in closers:
if not s:
return False
elif s[-1] != seeking.get(c):
return False
else:
s.pop()
return len(s) == 0
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_valid_short_code(self):
result = is_valid('()')
self.assertTrue(result)
def test_valid_longer_code(self):
result = is_valid('([]{[]})[]{{}()}')
self.assertTrue(result)
def test_interleaved_openers_and_closers(self):
result = is_valid('([)]')
self.assertFalse(result)
def test_mismatched_opener_and_closer(self):
result = is_valid('([][]}')
self.assertFalse(result)
def test_missing_closer(self):
result = is_valid('[[]()')
self.assertFalse(result)
def test_extra_closer(self):
result = is_valid('[[]]())')
self.assertFalse(result)
def test_empty_string(self):
result = is_valid('')
self.assertTrue(result)
unittest.main(verbosity=2)

View file

@ -0,0 +1,121 @@
import unittest
################################################################################
# Implementation
################################################################################
# is_leaf :: Node(a) -> Boolean
def is_leaf(node):
return not node.left and not node.right
# is_binary_search_tree :: Node(Integer) -> Set(Int) -> Set(Int) -> Boolean
def is_binary_search_tree_a(node, la=set(), ra=set()):
"""My first solution for this problem."""
for x in la:
if not node.value < x:
return False
for x in ra:
if not node.value > x:
return False
if is_leaf(node):
return True
elif not node.left:
return is_binary_search_tree(
node.right,
la=la,
ra=ra ^ {node.value},
)
elif not node.right:
return is_binary_search_tree(node.left, la=la ^ {node.value}, ra=ra)
else:
return all([
is_binary_search_tree(node.left, la=la ^ {node.value}, ra=ra),
is_binary_search_tree(node.right, la=la, ra=ra ^ {node.value})
])
# is_binary_search_tree :: Node(Int) -> Maybe(Int) -> Maybe(Int) -> Boolean
def is_binary_search_tree(node, lb=None, ub=None):
if lb:
if node.value < lb:
return False
if ub:
if node.value > ub:
return False
if is_leaf(node):
return True
elif not node.right:
return is_binary_search_tree(node.left, lb=lb, ub=node.value)
elif not node.left:
return is_binary_search_tree(node.right, lb=node.value, ub=ub)
else:
return is_binary_search_tree(
node.left, lb=lb, ub=node.value) and is_binary_search_tree(
node.right, lb=node.value, ub=ub)
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
class BinaryTreeNode(object):
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def insert_left(self, value):
self.left = Test.BinaryTreeNode(value)
return self.left
def insert_right(self, value):
self.right = Test.BinaryTreeNode(value)
return self.right
def test_valid_full_tree(self):
tree = Test.BinaryTreeNode(50)
left = tree.insert_left(30)
right = tree.insert_right(70)
left.insert_left(10)
left.insert_right(40)
right.insert_left(60)
right.insert_right(80)
result = is_binary_search_tree(tree)
self.assertTrue(result)
def test_both_subtrees_valid(self):
tree = Test.BinaryTreeNode(50)
left = tree.insert_left(30)
right = tree.insert_right(80)
left.insert_left(20)
left.insert_right(60)
right.insert_left(70)
right.insert_right(90)
result = is_binary_search_tree(tree)
self.assertFalse(result)
def test_descending_linked_list(self):
tree = Test.BinaryTreeNode(50)
left = tree.insert_left(40)
left_left = left.insert_left(30)
left_left_left = left_left.insert_left(20)
left_left_left.insert_left(10)
result = is_binary_search_tree(tree)
self.assertTrue(result)
def test_out_of_order_linked_list(self):
tree = Test.BinaryTreeNode(50)
right = tree.insert_right(70)
right_right = right.insert_right(60)
right_right.insert_right(80)
result = is_binary_search_tree(tree)
self.assertFalse(result)
def test_one_node_tree(self):
tree = Test.BinaryTreeNode(50)
result = is_binary_search_tree(tree)
self.assertTrue(result)
unittest.main(verbosity=2)

View file

@ -0,0 +1,91 @@
import unittest
################################################################################
# Implementation
################################################################################
def is_first_come_first_served(to, di, xs):
# All the guards, assertions we should need.
if to == di == xs == []:
return True
elif to == di == []:
return False
elif to == []:
return di == xs
elif to == []:
return di == xs
elif di == []:
return to == xs
elif xs == []:
return False
elif len(xs) != (len(to) + len(di)):
return False
fst, snd = to, di
if xs[0] == to[0]:
fst, snd = to, di
elif xs[0] == di[0]:
fst, snd = di, to
else:
return False
fst_done, snd_done = False, False
fi, si = 1, 0
for i in range(1, len(xs)):
# Short-circuit and avoid index-out-of-bounds without introducing overly
# defensive, sloppy code.
if fst_done:
return snd[si:] == xs[i:]
elif snd_done:
return fst[fi:] == xs[i:]
if fst[fi] == xs[i]:
fi += 1
elif snd[si] == xs[i]:
si += 1
else:
return False
fst_done, snd_done = fi == len(fst), si == len(snd)
return True
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_both_registers_have_same_number_of_orders(self):
result = is_first_come_first_served([1, 4, 5], [2, 3, 6],
[1, 2, 3, 4, 5, 6])
self.assertTrue(result)
def test_registers_have_different_lengths(self):
result = is_first_come_first_served([1, 5], [2, 3, 6], [1, 2, 6, 3, 5])
self.assertFalse(result)
def test_one_register_is_empty(self):
result = is_first_come_first_served([], [2, 3, 6], [2, 3, 6])
self.assertTrue(result)
def test_served_orders_is_missing_orders(self):
result = is_first_come_first_served([1, 5], [2, 3, 6], [1, 6, 3, 5])
self.assertFalse(result)
def test_served_orders_has_extra_orders(self):
result = is_first_come_first_served([1, 5], [2, 3, 6],
[1, 2, 3, 5, 6, 8])
self.assertFalse(result)
def test_one_register_has_extra_orders(self):
result = is_first_come_first_served([1, 9], [7, 8], [1, 7, 8])
self.assertFalse(result)
def test_one_register_has_unserved_orders(self):
result = is_first_come_first_served([55, 9], [7, 8], [1, 7, 8, 9])
self.assertFalse(result)
unittest.main(verbosity=2)

View file

@ -0,0 +1,71 @@
import unittest
from math import floor
################################################################################
# Solution
################################################################################
def max_duffel_bag_value(xs, cap):
ct = (cap + 1)
maxes = [0] * ct
for c in range(cap + 1):
for w, v in xs:
if w == 0 and v > 0:
return float('inf')
if w == c:
maxes[c:] = [max(maxes[c], v)] * (ct - c)
elif w < c:
d = c - w
maxes[c:] = [max(maxes[c], v + maxes[d])] * (ct - c)
else:
continue
return maxes[cap]
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_one_cake(self):
actual = max_duffel_bag_value([(2, 1)], 9)
expected = 4
self.assertEqual(actual, expected)
def test_two_cakes(self):
actual = max_duffel_bag_value([(4, 4), (5, 5)], 9)
expected = 9
self.assertEqual(actual, expected)
def test_only_take_less_valuable_cake(self):
actual = max_duffel_bag_value([(4, 4), (5, 5)], 12)
expected = 12
self.assertEqual(actual, expected)
def test_lots_of_cakes(self):
actual = max_duffel_bag_value([(2, 3), (3, 6), (5, 1), (6, 1), (7, 1),
(8, 1)], 7)
expected = 12
self.assertEqual(actual, expected)
def test_value_to_weight_ratio_is_not_optimal(self):
actual = max_duffel_bag_value([(51, 52), (50, 50)], 100)
expected = 100
self.assertEqual(actual, expected)
def test_zero_capacity(self):
actual = max_duffel_bag_value([(1, 2)], 0)
expected = 0
self.assertEqual(actual, expected)
def test_cake_with_zero_value_and_weight(self):
actual = max_duffel_bag_value([(0, 0), (2, 1)], 7)
expected = 3
self.assertEqual(actual, expected)
def test_cake_with_non_zero_value_and_zero_weight(self):
actual = max_duffel_bag_value([(0, 5)], 5)
expected = float('inf')
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,57 @@
import unittest
from math import floor
################################################################################
# Solution
################################################################################
# change_possibilities :: Int -> [Int] -> Int
def change_possibilities(n, xs):
combinations = [0] * (n + 1)
combinations[0] = 1
for x in xs:
for i in range(len(combinations)):
if i >= x:
combinations[i] += combinations[i - x]
return combinations[n]
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_sample_input(self):
actual = change_possibilities(4, (1, 2, 3))
expected = 4
self.assertEqual(actual, expected)
def test_one_way_to_make_zero_cents(self):
actual = change_possibilities(0, (1, 2))
expected = 1
self.assertEqual(actual, expected)
def test_no_ways_if_no_coins(self):
actual = change_possibilities(1, ())
expected = 0
self.assertEqual(actual, expected)
def test_big_coin_value(self):
actual = change_possibilities(5, (25, 50))
expected = 0
self.assertEqual(actual, expected)
def test_big_target_amount(self):
actual = change_possibilities(50, (5, 10))
expected = 6
self.assertEqual(actual, expected)
def test_change_for_one_dollar(self):
actual = change_possibilities(100, (1, 5, 10, 25, 50))
expected = 292
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,78 @@
from itertools import product
from random import choice
from time import sleep
from os import system
from math import floor
from colorama import Back, Fore, Style
################################################################################
# Simulation of Conway's Game of Life. The goal here was to write this with a
# small amount of code as a proof-of-concept that could be run in the terminal.
#
# If you'd like to tinker with the rules, see the conditionals defined in the
# `advance/1` function. For other parameters, like the board size and refresh
# rate, refer to the while-loop defined at the bottom of this file.
################################################################################
def init_board(n, init_alive_percentage):
"""Initialize a board of size `n` by `n`. Supply a percentage,
`init_alive_percentage`, representing the number of cells in the board that
should be alive from the start."""
alive_count = floor(n * init_alive_percentage)
distribution = [True] * alive_count + [False] * (n - alive_count)
return [[choice(distribution) for _ in range(n)] for _ in range(n)]
def neighbors(coord, board):
"""Return the neighbors for a given `coord` on a `board`."""
n = len(board)
row, col = coord
return [
board[(row + row_d) % n][(col + col_d) % n]
for row_d, col_d in product([-1, 0, 1], [-1, 0, 1])
if (row_d, col_d) != (0, 0)
]
def advance(board):
"""Advance the state of the `board` from T[n] to T[n+1]."""
n = len(board)
new_board = [[False for _ in range(n)] for _ in range(n)]
for row in range(n):
for col in range(n):
alive_count = len([x for x in neighbors((row, col), board) if x])
# Loneliness
if alive_count == 0:
new_board[row][col] = False
# Status Quo
elif alive_count == 1:
new_board[row][col] = board[row][col]
# Cooperation
elif alive_count == 2:
new_board[row][col] = True
# Resource starvation
elif alive_count >= 3:
new_board[row][col] = False
return new_board
def print_board(board):
"""Print the game `board` in a human-readable way."""
result = ''
for row in board:
for col in row:
if col:
result += Back.GREEN + '1 ' + Style.RESET_ALL
else:
result += Back.RED + '0 ' + Style.RESET_ALL
result += '\n'
print(result)
board = init_board(100, 0.50)
while True:
system('clear')
print_board(board)
sleep(0.15)
board = advance(board)

View file

@ -0,0 +1,60 @@
import unittest
################################################################################
# Solution
################################################################################
def delete_node(x):
if not x.next:
raise Exception('Cannot delete the last node in a linked list.')
else:
x.value = x.next.value
x.next = x.next.next
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
class LinkedListNode(object):
def __init__(self, value, next=None):
self.value = value
self.next = next
def get_values(self):
node = self
values = []
while node is not None:
values.append(node.value)
node = node.next
return values
def setUp(self):
self.fourth = Test.LinkedListNode(4)
self.third = Test.LinkedListNode(3, self.fourth)
self.second = Test.LinkedListNode(2, self.third)
self.first = Test.LinkedListNode(1, self.second)
def test_node_at_beginning(self):
delete_node(self.first)
actual = self.first.get_values()
expected = [2, 3, 4]
self.assertEqual(actual, expected)
def test_node_in_middle(self):
delete_node(self.second)
actual = self.first.get_values()
expected = [1, 3, 4]
self.assertEqual(actual, expected)
def test_node_at_end(self):
with self.assertRaises(Exception):
delete_node(self.fourth)
def test_one_node_in_list(self):
unique = Test.LinkedListNode(1)
with self.assertRaises(Exception):
delete_node(unique)
unittest.main(verbosity=2)

View file

@ -0,0 +1,65 @@
from random import choice
class Node(object):
def __init__(self, value=None, left=None, right=None):
self.value = value
self.left = left
self.right = left
def p(node, indent=0):
print(indent * ' ' + '|-' + str(node.value))
if node.left is not None:
p(node.left, indent=indent + 2)
if node.right is not None:
p(node.right, indent=indent + 2)
# read trees (i.e. traversing, parsing)
# write trees (i.e. generating, printing)
def random(d=0):
left = None
right = None
if choice([True, False]):
left = random(d + 1)
if choice([True, False]):
right = random(d + 1)
return Node(
value=d,
left=left,
right=right,
)
################################################################################
# DFTs can be:
# - imperative (mutable)
# - functional (immutable)
# - iterative
# - recursive
################################################################################
# Iterative
def traverse(node, f):
stack = [(node, 0)]
while len(stack):
node, depth = stack.pop()
f(node, depth)
print(depth)
if node.left is not None:
stack.append((node.left, depth + 1))
if node.right is not None:
stack.append((node.right, depth + 1))
print('----------------------------------------------------------------------')
for _ in range(10):
traverse(random(), lambda _, d: print(d))
print()

View file

@ -0,0 +1,48 @@
from collections import deque
from heapq import heappush, heappop
from fixtures import weighted_graph
def put(t, x, xs):
if t == 'stack':
return xs.append(x)
if t == 'queue':
return xs.append(x)
if t == 'priority':
return heappush(xs, x)
def pop(t, xs):
if t == 'stack':
return xs.pop()
if t == 'queue':
return xs.popleft()
if t == 'priority':
return heappop(xs)
# shortest_path :: Vertex -> Vertex -> Graph -> [Vertex]
def shortest_path(a, b, g):
"""Returns the shortest path from vertex a to vertex b in graph g."""
t = 'priority'
xs = []
seen = set()
# Map(Weight, [Vertex])
m = {}
put(t, (0, [a], a), xs)
while xs:
w0, path, v = pop(t, xs)
seen.add(v)
if v == b:
m[w0] = path
for w1, x in g.get(v):
if x not in seen:
put(t, (w0 + w1, path + [x], x), xs)
return m
print(shortest_path('a', 'f', graph_a))

View file

@ -0,0 +1,56 @@
import unittest
################################################################################
# Solution
################################################################################
def find_duplicate(xs):
self_ref_count = 0
for i in range(len(xs)):
if xs[i] == i + 1:
self_ref_count += 1
hops = len(xs) - 1 - self_ref_count
current = xs[-1]
while hops > 0:
current = xs[current - 1]
hops -= 1
return current
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
# TODO: Debug why this fails.
def test_darren_from_interview_cake(self):
actual = find_duplicate([4, 1, 8, 3, 2, 7, 6, 5, 4])
expected = 4
self.assertEqual(actual, expected)
def test_just_the_repeated_number(self):
actual = find_duplicate([1, 1])
expected = 1
self.assertEqual(actual, expected)
def test_short_list(self):
actual = find_duplicate([1, 2, 3, 2])
expected = 2
self.assertEqual(actual, expected)
def test_last_cycle(self):
actual = find_duplicate([3, 4, 2, 3, 1, 5])
expected = 3
self.assertEqual(actual, expected)
def test_medium_list(self):
actual = find_duplicate([1, 2, 5, 5, 5, 5])
expected = 5
self.assertEqual(actual, expected)
def test_long_list(self):
actual = find_duplicate([4, 1, 4, 8, 3, 2, 7, 6, 5])
expected = 4
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,61 @@
from math import floor
import unittest
################################################################################
# Solution
################################################################################
def bounds(r):
ct = len(r)
if ct % 2 == 0:
h = int(ct / 2)
return ct, h
else:
h = floor(ct / 2)
return ct, h
def find_repeat(xs):
ct, h = bounds(xs)
rl = range(1, h + 1)
rr = range(h + 1, ct)
while True:
nl = len([None for x in xs if x in rl])
nr = len([None for x in xs if x in rr])
branch = rl if nl > nr else rr
if len(branch) == 1:
return branch[0]
ct, h = bounds(branch)
rl = range(branch[0], branch[0])
rr = range(branch[0] + h, branch[-1] + 1)
raise Exception(
'We could not find any duplicates in xs. Perhaps xs did not adhere to the usage contract.'
)
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_just_the_repeated_number(self):
actual = find_repeat([1, 1])
expected = 1
self.assertEqual(actual, expected)
def test_short_list(self):
actual = find_repeat([1, 2, 3, 2])
expected = 2
self.assertEqual(actual, expected)
def test_medium_list(self):
actual = find_repeat([1, 2, 5, 5, 5, 5])
expected = 5
self.assertEqual(actual, expected)
def test_long_list(self):
actual = find_repeat([4, 1, 4, 8, 3, 2, 7, 6, 5])
expected = 4
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,59 @@
import unittest
################################################################################
# Solution
################################################################################
def find_rotation_point(xs):
"""Usage of `visited` here is a hack, but works for the test cases
(gulp)."""
i = 0
j = round(len(xs) / 2)
result = None
visited = set()
while not result:
if i in visited:
i += 1
if j in visited:
j -= 1
visited.add(i)
visited.add(j)
if xs[j - 1] > xs[j]:
result = j
elif xs[i] < xs[j]:
i = j
j += round((len(xs) - j) / 2)
elif xs[i] >= xs[j]:
i = j
j -= round((j - i) / 2)
return result
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_small_list(self):
actual = find_rotation_point(['cape', 'cake'])
expected = 1
self.assertEqual(actual, expected)
def test_medium_list(self):
actual = find_rotation_point(
['grape', 'orange', 'plum', 'radish', 'apple'])
expected = 4
self.assertEqual(actual, expected)
def test_large_list(self):
actual = find_rotation_point([
'ptolemaic', 'retrograde', 'supplant', 'undulate', 'xenoepist',
'asymptote', 'babka', 'banoffee', 'engender', 'karpatka',
'othellolagkage'
])
expected = 5
self.assertEqual(actual, expected)
# Are we missing any edge cases?
unittest.main(verbosity=2)

View file

@ -0,0 +1,45 @@
import unittest
################################################################################
# Solution
################################################################################
def find_unique_delivery_id(xs):
a = 0
for x in xs:
a ^= x
return a
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_one_drone(self):
actual = find_unique_delivery_id([1])
expected = 1
self.assertEqual(actual, expected)
def test_unique_id_comes_first(self):
actual = find_unique_delivery_id([1, 2, 2])
expected = 1
self.assertEqual(actual, expected)
def test_unique_id_comes_last(self):
actual = find_unique_delivery_id([3, 3, 2, 2, 1])
expected = 1
self.assertEqual(actual, expected)
def test_unique_id_in_middle(self):
actual = find_unique_delivery_id([3, 2, 1, 2, 3])
expected = 1
self.assertEqual(actual, expected)
def test_many_drones(self):
actual = find_unique_delivery_id(
[2, 5, 4, 8, 6, 3, 1, 4, 2, 3, 6, 5, 1])
expected = 8
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,110 @@
# Using this module to store commonly used, but annoying to create, data
# structures for my test inputs.
#
# Use like:
# from fixtures import graph_a
################################################################################
# Constants
################################################################################
edge_list = [
('a', 'b'),
('a', 'c'),
('a', 'e'),
('b', 'c'),
('b', 'd'),
('c', 'e'),
('d', 'f'),
('e', 'd'),
('e', 'f'),
]
unweighted_graph = {
'a': {'b', 'c', 'e'},
'b': {'c', 'd'},
'c': {'e'},
'd': {'f'},
'e': {'d', 'f'},
'f': set(),
}
adjacencies = {
'a': {
'a': False,
'b': False
},
'a': [],
'a': [],
'a': [],
'a': [],
'a': [],
'a': [],
}
weighted_graph = {
'a': {(4, 'b'), (2, 'c'), (4, 'e')},
'b': {(5, 'c'), (10, 'd')},
'c': {(3, 'e')},
'd': {(11, 'f')},
'e': {(4, 'd'), (5, 'f')},
'f': set(),
}
# This is `weighted_graph` with each of its weighted edges "expanded".
expanded_weights_graph = {
'a': ['b-1', 'c-1', 'e-1'],
'b-1': ['b-2'],
'b-2': ['b-3'],
'b-3': ['b'],
'c-1': ['c'],
'e-1': ['e-2'],
'e-2': ['e-3'],
'e-3': ['e'],
# and so on...
}
unweighted_digraph = {
'5': {'2', '0'},
'4': {'0', '1'},
'3': {'1'},
'2': {'3'},
'1': set(),
'0': set(),
}
################################################################################
# Functions
################################################################################
def vertices(xs):
result = set()
for a, b in xs:
result.add(a)
result.add(b)
return result
def edges_to_neighbors(xs):
result = {v: set() for v in vertices(xs)}
for a, b in xs:
result[a].add(b)
return result
def neighbors_to_edges(xs):
result = []
for k, ys in xs.items():
for y in ys:
result.append((k, y))
return result
def edges_to_adjacencies(xs):
return xs
# Skipping handling adjacencies because I cannot think of a reasonable use-case
# for it when the vertex labels are items other than integers. I can think of
# ways of handling this, but none excite me.

View file

@ -0,0 +1,180 @@
import unittest
from collections import deque
################################################################################
# Solution
################################################################################
class GraphNode:
def __init__(self, label):
self.label = label
self.neighbors = set()
self.color = None
# color_graph :: G(V, E) -> Set(Color) -> IO ()
def color_graph(graph, colors):
q = deque()
seen = set()
q.append(graph[0])
while q:
node = q.popleft()
illegal = {n.color for n in node.neighbors}
for x in colors:
if x not in illegal:
node.color = x
seen.add(node)
for x in node.neighbors:
if x not in seen:
q.append(x)
# TODO: Is this the best way to traverse separate graphs?
for x in graph:
if x not in seen:
q.append(x)
return 0
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def setUp(self):
self.colors = frozenset([
'red',
'green',
'blue',
'orange',
'yellow',
'white',
])
def assertGraphColoring(self, graph, colors):
self.assertGraphHasColors(graph, colors)
self.assertGraphColorLimit(graph)
for node in graph:
self.assertNodeUniqueColor(node)
def assertGraphHasColors(self, graph, colors):
for node in graph:
msg = 'Node %r color %r not in %r' % (node.label, node.color,
colors)
self.assertIn(node.color, colors, msg=msg)
def assertGraphColorLimit(self, graph):
max_degree = 0
colors_found = set()
for node in graph:
degree = len(node.neighbors)
max_degree = max(degree, max_degree)
colors_found.add(node.color)
max_colors = max_degree + 1
used_colors = len(colors_found)
msg = 'Used %d colors and expected %d at most' % (used_colors,
max_colors)
self.assertLessEqual(used_colors, max_colors, msg=msg)
def assertNodeUniqueColor(self, node):
for adjacent in node.neighbors:
msg = 'Adjacent nodes %r and %r have the same color %r' % (
node.label,
adjacent.label,
node.color,
)
self.assertNotEqual(node.color, adjacent.color, msg=msg)
def test_line_graph(self):
node_a = GraphNode('a')
node_b = GraphNode('b')
node_c = GraphNode('c')
node_d = GraphNode('d')
node_a.neighbors.add(node_b)
node_b.neighbors.add(node_a)
node_b.neighbors.add(node_c)
node_c.neighbors.add(node_b)
node_c.neighbors.add(node_d)
node_d.neighbors.add(node_c)
graph = [node_a, node_b, node_c, node_d]
tampered_colors = list(self.colors)
color_graph(graph, tampered_colors)
self.assertGraphColoring(graph, self.colors)
def test_separate_graph(self):
node_a = GraphNode('a')
node_b = GraphNode('b')
node_c = GraphNode('c')
node_d = GraphNode('d')
node_a.neighbors.add(node_b)
node_b.neighbors.add(node_a)
node_c.neighbors.add(node_d)
node_d.neighbors.add(node_c)
graph = [node_a, node_b, node_c, node_d]
tampered_colors = list(self.colors)
color_graph(graph, tampered_colors)
self.assertGraphColoring(graph, self.colors)
def test_triangle_graph(self):
node_a = GraphNode('a')
node_b = GraphNode('b')
node_c = GraphNode('c')
node_a.neighbors.add(node_b)
node_a.neighbors.add(node_c)
node_b.neighbors.add(node_a)
node_b.neighbors.add(node_c)
node_c.neighbors.add(node_a)
node_c.neighbors.add(node_b)
graph = [node_a, node_b, node_c]
tampered_colors = list(self.colors)
color_graph(graph, tampered_colors)
self.assertGraphColoring(graph, self.colors)
def test_envelope_graph(self):
node_a = GraphNode('a')
node_b = GraphNode('b')
node_c = GraphNode('c')
node_d = GraphNode('d')
node_e = GraphNode('e')
node_a.neighbors.add(node_b)
node_a.neighbors.add(node_c)
node_b.neighbors.add(node_a)
node_b.neighbors.add(node_c)
node_b.neighbors.add(node_d)
node_b.neighbors.add(node_e)
node_c.neighbors.add(node_a)
node_c.neighbors.add(node_b)
node_c.neighbors.add(node_d)
node_c.neighbors.add(node_e)
node_d.neighbors.add(node_b)
node_d.neighbors.add(node_c)
node_d.neighbors.add(node_e)
node_e.neighbors.add(node_b)
node_e.neighbors.add(node_c)
node_e.neighbors.add(node_d)
graph = [node_a, node_b, node_c, node_d, node_e]
tampered_colors = list(self.colors)
color_graph(graph, tampered_colors)
self.assertGraphColoring(graph, self.colors)
def test_loop_graph(self):
node_a = GraphNode('a')
node_a.neighbors.add(node_a)
graph = [node_a]
tampered_colors = list(self.colors)
with self.assertRaises(Exception):
color_graph(graph, tampered_colors)
unittest.main(verbosity=2)

View file

@ -0,0 +1,39 @@
from graphviz import Digraph
from collections import deque
from fixtures import weighted_graph
# There are three ways to model a graph:
# 1. Edge list: [(Vertex, Vertex)]
# 2. Neighbors table: Map(Vertex, [Vertex])
# 3. Adjacency matrix: [[Boolean]]
#
# The following graph is a neighbors table.
# to_graphviz :: Vertex -> Map(Vertex, [(Vertex, Weight)]) -> String
def to_graphviz(start, g):
"""Compiles the graph into GraphViz."""
d = Digraph()
q = deque()
seen = set()
q.append(start)
while q:
v = q.popleft()
if v in seen:
continue
d.node(v, label=v)
for w, x in g[v]:
d.edge(v, x, label=str(w))
q.append(x)
seen.add(v)
return d.source
with open('/tmp/test.gv', 'w') as f:
src = to_graphviz('a', weighted_graph)
f.write(src)
print('/tmp/test.gv created!')

View file

@ -0,0 +1,89 @@
import unittest
################################################################################
# Solution
################################################################################
# f :: [Int] -> Int
def highest_product_of_3(xs):
"""Here we're greedily storing:
- current max
- largest product of two
- largest positive number
- second largest positive number
- largest negative number
"""
if len(xs) < 3:
raise Exception
cm = None
ld = xs[0] * xs[1]
l2 = min(xs[0], xs[1])
if xs[0] < 0 or xs[1] < 0:
ln = min(xs[0], xs[1])
else:
ln = 1
l = max(xs[0], xs[1])
for x in xs[2:]:
if not cm:
cm = max(x * ln * l, ld * x, x * l * l2) # beware
ld = max(ld, x * ln, x * l)
ln = min(ln, x)
l = max(l, x)
if x < l:
l2 = max(l2, x)
else:
cm = max(cm, x * ln * l, x * ld, x * l * l2)
ld = max(ld, x * ln, x * l)
ln = min(ln, x)
l = max(l, x)
if x < l:
l2 = max(l2, x)
return cm
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_short_list(self):
actual = highest_product_of_3([1, 2, 3, 4])
expected = 24
self.assertEqual(actual, expected)
def test_longer_list(self):
actual = highest_product_of_3([6, 1, 3, 5, 7, 8, 2])
expected = 336
self.assertEqual(actual, expected)
def test_list_has_one_negative(self):
actual = highest_product_of_3([-5, 4, 8, 2, 3])
expected = 96
self.assertEqual(actual, expected)
def test_list_has_two_negatives(self):
actual = highest_product_of_3([-10, 1, 3, 2, -10])
expected = 300
self.assertEqual(actual, expected)
def test_list_is_all_negatives(self):
actual = highest_product_of_3([-5, -1, -3, -2])
expected = -6
self.assertEqual(actual, expected)
def test_error_with_empty_list(self):
with self.assertRaises(Exception):
highest_product_of_3([])
def test_error_with_one_number(self):
with self.assertRaises(Exception):
highest_product_of_3([1])
def test_error_with_two_numbers(self):
with self.assertRaises(Exception):
highest_product_of_3([1, 1])
unittest.main(verbosity=2)

View file

@ -0,0 +1,35 @@
# possible :: Int -> [Int] -> Bool
def possible(flight_duration, film_durations):
seeking = set()
for x in film_durations:
if x in seeking:
return True
else:
seeking.add(flight_duration - x)
return False
should = [
(10, [1, 9, 8, 8, 8]),
(10, [1, 9]),
(10, [1, 9, 5, 5, 6]),
(1, [0.5, 0.5]),
(1, [0.5, 0.5]),
]
for a, b in should:
print("Testing: %s %s" % (a, b))
assert possible(a, b)
shouldnt = [
(10, [1, 10, 1, 2, 1, 12]),
(1, [0.25, 0.25, 0.25, 0.25]),
(5, [1, 2, 2]),
]
for a, b in shouldnt:
print("Testing: %s %s" % (a, b))
assert not possible(a, b)
print("Tests pass")

View file

@ -0,0 +1,38 @@
import unittest
from math import floor
def knapify(xs, capacity=None):
assert capacity is not None
n = len(xs)
# For 0/1 Knapsack, we must use a table, since this will encode which values
# work for which items. This is cleaner than including a separate data
# structure to capture it.
maxes = [[0 for x in range(capacity + 1)] for x in range(n + 1)]
# Build table maxes[][] in bottom up manner
for row in range(n + 1):
for col in range(capacity + 1):
if row == 0 or col == 0:
maxes[row][col] = 0
elif xs[row - 1][0] <= col:
maxes[row][col] = max(
xs[row - 1][1] + maxes[row - 1][col - xs[row - 1][0]],
maxes[row - 1][col])
else:
maxes[row][col] = maxes[row - 1][col]
return maxes[-1][capacity]
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_one_cake(self):
actual = knapify([(3, 10), (2, 15), (7, 2), (12, 20)], capacity=12)
expected = None
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,82 @@
import unittest
################################################################################
# Solution
################################################################################
def length(x):
if not x:
return 0
else:
count = 1
while x:
x = x.next
count += 1
return count
def kth_to_last_node(k, x):
hops = length(x) - 1
dest = hops - k
if k == 0:
raise Exception("Our God doesn't support this kind of behavior.")
if dest < 0:
raise Exception('Value k to high for list.')
while dest > 0:
x = x.next
dest -= 1
return x
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
class LinkedListNode(object):
def __init__(self, value, next=None):
self.value = value
self.next = next
def get_values(self):
node = self
values = []
while node is not None:
values.append(node.value)
node = node.next
return values
def setUp(self):
self.fourth = Test.LinkedListNode(4)
self.third = Test.LinkedListNode(3, self.fourth)
self.second = Test.LinkedListNode(2, self.third)
self.first = Test.LinkedListNode(1, self.second)
def test_first_to_last_node(self):
actual = kth_to_last_node(1, self.first)
expected = self.fourth
self.assertEqual(actual, expected)
def test_second_to_last_node(self):
actual = kth_to_last_node(2, self.first)
expected = self.third
self.assertEqual(actual, expected)
def test_first_node(self):
actual = kth_to_last_node(4, self.first)
expected = self.first
self.assertEqual(actual, expected)
def test_k_greater_than_linked_list_length(self):
with self.assertRaises(Exception):
kth_to_last_node(5, self.first)
def test_k_is_zero(self):
with self.assertRaises(Exception):
kth_to_last_node(0, self.first)
unittest.main(verbosity=2)

View file

@ -0,0 +1,107 @@
import unittest
class Stack(object):
def __init__(self):
"""Initialize an empty stack"""
self.items = []
def push(self, item):
"""Push a new item onto the stack"""
self.items.append(item)
def pop(self):
"""Remove and return the last item"""
# If the stack is empty, return None
# (it would also be reasonable to throw an exception)
if not self.items:
return None
return self.items.pop()
def peek(self):
"""Return the last item without removing it"""
if not self.items:
return None
return self.items[-1]
class MaxStack(object):
# Implement the push, pop, and get_max methods
def __init__(self):
self.m = Stack()
self.stack = Stack()
def push(self, item):
if self.m.peek() is None:
self.m.push(item)
elif item >= self.m.peek():
self.m.push(item)
self.stack.push(item)
def pop(self):
x = self.stack.pop()
if x == self.m.peek():
self.m.pop()
return x
def get_max(self):
return self.m.peek()
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_stack_usage(self):
max_stack = MaxStack()
max_stack.push(5)
actual = max_stack.get_max()
expected = 5
self.assertEqual(actual, expected)
max_stack.push(4)
max_stack.push(7)
max_stack.push(7)
max_stack.push(8)
actual = max_stack.get_max()
expected = 8
self.assertEqual(actual, expected)
actual = max_stack.pop()
expected = 8
self.assertEqual(actual, expected)
actual = max_stack.get_max()
expected = 7
self.assertEqual(actual, expected)
actual = max_stack.pop()
expected = 7
self.assertEqual(actual, expected)
actual = max_stack.get_max()
expected = 7
self.assertEqual(actual, expected)
actual = max_stack.pop()
expected = 7
self.assertEqual(actual, expected)
actual = max_stack.get_max()
expected = 5
self.assertEqual(actual, expected)
actual = max_stack.pop()
expected = 4
self.assertEqual(actual, expected)
actual = max_stack.get_max()
expected = 5
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,88 @@
import unittest
################################################################################
# Solution
################################################################################
def contains_cycle(x):
if not x:
return False
elif not x.next:
return False
a = x
b = x.next
while b.next:
if a == b:
return True
a = a.next
b = b.next.next
return False
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
class LinkedListNode(object):
def __init__(self, value, next=None):
self.value = value
self.next = next
def test_linked_list_with_no_cycle(self):
fourth = Test.LinkedListNode(4)
third = Test.LinkedListNode(3, fourth)
second = Test.LinkedListNode(2, third)
first = Test.LinkedListNode(1, second)
result = contains_cycle(first)
self.assertFalse(result)
def test_cycle_loops_to_beginning(self):
fourth = Test.LinkedListNode(4)
third = Test.LinkedListNode(3, fourth)
second = Test.LinkedListNode(2, third)
first = Test.LinkedListNode(1, second)
fourth.next = first
result = contains_cycle(first)
self.assertTrue(result)
def test_cycle_loops_to_middle(self):
fifth = Test.LinkedListNode(5)
fourth = Test.LinkedListNode(4, fifth)
third = Test.LinkedListNode(3, fourth)
second = Test.LinkedListNode(2, third)
first = Test.LinkedListNode(1, second)
fifth.next = third
result = contains_cycle(first)
self.assertTrue(result)
def test_two_node_cycle_at_end(self):
fifth = Test.LinkedListNode(5)
fourth = Test.LinkedListNode(4, fifth)
third = Test.LinkedListNode(3, fourth)
second = Test.LinkedListNode(2, third)
first = Test.LinkedListNode(1, second)
fifth.next = fourth
result = contains_cycle(first)
self.assertTrue(result)
def test_empty_list(self):
result = contains_cycle(None)
self.assertFalse(result)
def test_one_element_linked_list_no_cycle(self):
first = Test.LinkedListNode(1)
result = contains_cycle(first)
self.assertFalse(result)
def test_one_element_linked_list_cycle(self):
first = Test.LinkedListNode(1)
first.next = first
result = contains_cycle(first)
self.assertTrue(result)
unittest.main(verbosity=2)

View file

@ -0,0 +1,28 @@
# merge :: [a] -> [a] -> [a]
# merge([], []): []
# merge(xs, []): xs
# merge([], ys): ys
# merge(xs@[x|xs'], ys@[y|ys'])
# when y =< x: cons(y, merge(xs, ys'))
# when x < y: cons(x, merge(xs', ys))
def merge(xs, ys):
if xs == [] and ys == []:
return []
elif ys == []:
return xs
elif xs == []:
return ys
else:
x = xs[0]
y = ys[0]
if y <= x:
return [y] + merge(xs, ys[1:])
else:
return [x] + merge(xs[1:], ys)
print(merge([3, 4, 6, 10, 11, 15],
[1, 5, 8, 12, 14, 19]))

View file

@ -0,0 +1,94 @@
import unittest
################################################################################
# Solution
################################################################################
# do_merge_ranges :: [(Int, Int)] -> [(Int, Int)] -> [(Int, Int)]
def do_merge_ranges(prev, xs):
if len(xs) == 0:
return prev
elif len(xs) == 1:
return prev + xs
else:
a1, a2 = xs[0]
b1, b2 = xs[1]
rest = xs[2:]
if b1 <= a2:
return do_merge_ranges(prev, [(a1, max(a2, b2))] + rest)
else:
return do_merge_ranges(prev + [(a1, a2)], [(b1, b2)] + rest)
# merge_ranges :: [(Int, Int)] -> [(Int, Int)]
def merge_ranges(xs):
xs = xs[:]
xs.sort()
return do_merge_ranges([], xs)
# merge_ranges_b :: [(Int, Int)] -> [(Int, Int)]
def merge_ranges_b(xs):
fi = 0
ci = 1
result = []
xs = xs[:]
xs.sort()
while ci < len(xs):
while ci < len(xs) and xs[ci][0] <= xs[fi][1]:
xs[fi] = xs[fi][0], max(xs[ci][1], xs[fi][1])
ci += 1
result.append(xs[fi])
fi = ci
ci += 1
if fi < len(xs):
result.append(xs[fi])
return result
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_meetings_overlap(self):
actual = merge_ranges([(1, 3), (2, 4)])
expected = [(1, 4)]
self.assertEqual(actual, expected)
def test_meetings_touch(self):
actual = merge_ranges([(5, 6), (6, 8)])
expected = [(5, 8)]
self.assertEqual(actual, expected)
def test_meeting_contains_other_meeting(self):
actual = merge_ranges([(1, 8), (2, 5)])
expected = [(1, 8)]
self.assertEqual(actual, expected)
def test_meetings_stay_separate(self):
actual = merge_ranges([(1, 3), (4, 8)])
expected = [(1, 3), (4, 8)]
self.assertEqual(actual, expected)
def test_multiple_merged_meetings(self):
actual = merge_ranges([(1, 4), (2, 5), (5, 8)])
expected = [(1, 8)]
self.assertEqual(actual, expected)
def test_meetings_not_sorted(self):
actual = merge_ranges([(5, 8), (1, 4), (6, 8)])
expected = [(1, 4), (5, 8)]
self.assertEqual(actual, expected)
def test_one_long_meeting_contains_smaller_meetings(self):
actual = merge_ranges([(1, 10), (2, 5), (6, 8), (9, 10), (10, 12)])
expected = [(1, 12)]
self.assertEqual(actual, expected)
def test_sample_input(self):
actual = merge_ranges([(0, 1), (3, 5), (4, 8), (10, 12), (9, 10)])
expected = [(0, 1), (3, 8), (9, 12)]
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,11 @@
strict graph {
Min -- {William, Jayden, Omar}
William -- {Min, Noam}
Jayden -- {Min, Amelia, Ren, Noam}
Adam -- {Amelia, Miguel, Sofia, Lucas}
Ren -- {Jayden, Omar}
Amelia -- {Jayden, Adam, Miguel}
Miguel -- {Amelia, Adam, Liam, Nathan}
Noam -- {Nathan, Jayden, William}
Omar -- {Ren, Min, Scott}
}

View file

@ -0,0 +1,97 @@
import unittest
from collections import deque
################################################################################
# Solution
################################################################################
# get_path :: G(V, E) -> V -> V -> Maybe([V])
def get_path(g, src, dst):
q = deque()
result = None
seen = set()
q.append(([], src))
if src not in g or dst not in g:
raise Exception
while q:
p, node = q.popleft()
seen.add(node)
if node == dst:
if not result:
result = p + [node]
elif len(p + [node]) < len(result):
result = p + [node]
else:
if node not in g:
raise Exception
for x in g.get(node):
if not x in seen:
q.append((p + [node], x))
return result
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def setUp(self):
self.graph = {
'a': ['b', 'c', 'd'],
'b': ['a', 'd'],
'c': ['a', 'e'],
'd': ['a', 'b'],
'e': ['c'],
'f': ['g'],
'g': ['f'],
}
def test_two_hop_path_1(self):
actual = get_path(self.graph, 'a', 'e')
expected = ['a', 'c', 'e']
self.assertEqual(actual, expected)
def test_two_hop_path_2(self):
actual = get_path(self.graph, 'd', 'c')
expected = ['d', 'a', 'c']
self.assertEqual(actual, expected)
def test_one_hop_path_1(self):
actual = get_path(self.graph, 'a', 'c')
expected = ['a', 'c']
self.assertEqual(actual, expected)
def test_one_hop_path_2(self):
actual = get_path(self.graph, 'f', 'g')
expected = ['f', 'g']
self.assertEqual(actual, expected)
def test_one_hop_path_3(self):
actual = get_path(self.graph, 'g', 'f')
expected = ['g', 'f']
self.assertEqual(actual, expected)
def test_zero_hop_path(self):
actual = get_path(self.graph, 'a', 'a')
expected = ['a']
self.assertEqual(actual, expected)
def test_no_path(self):
actual = get_path(self.graph, 'a', 'f')
expected = None
self.assertEqual(actual, expected)
def test_start_node_not_present(self):
with self.assertRaises(Exception):
get_path(self.graph, 'h', 'a')
def test_end_node_not_present(self):
with self.assertRaises(Exception):
get_path(self.graph, 'a', 'h')
unittest.main(verbosity=2)

View file

@ -0,0 +1,78 @@
# Write a function with the following type signature:L
# equal? :: String -> String -> Bool
#
# Determine equality between two inputs with backspace characters encoded as
# "<".
################################################################################
# Solution 1
################################################################################
# from collections import deque
# def equal(a, b):
# sa = deque()
# sb = deque()
# for c in a:
# if c == '<':
# sa.pop()
# else:
# sa.append(c)
# for c in b:
# if c == '<':
# sb.pop()
# else:
# sb.append(c)
# return sa == sb
################################################################################
# Solution 2
################################################################################
def handle_dels(num_dels, i, xs):
if i < 0:
return -1
while xs[i] == '<':
num_dels += 1
i -= 1
while num_dels > 0 and xs[i] != '<':
num_dels -= 1
i -= 1
if xs[i] == '<':
return handle_dels(num_dels, i, xs)
else:
return i
def update_index(i, xs):
# TODO: Indexing into non-available parts of a string.
if xs[i] != '<' and xs[i - 1] != '<':
return i - 1
elif xs[i - 1] == '<':
return handle_dels(0, i - 1, xs)
def equal(a, b):
ia = len(a) - 1
ib = len(b) - 1
while ia >= 0 and ib >= 0:
if a[ia] != b[ib]:
return False
ia = update_index(ia, a)
ib = update_index(ib, b)
if ia != 0:
return update_index(ia, a) <= -1
if ib != 0:
return update_index(ib, b) <= -1
return True

View file

@ -0,0 +1,59 @@
import unittest
################################################################################
# Solution
################################################################################
def fib(n):
"""This should be accomplishable in O(1) space."""
if n in {0, 1}:
return n
a = 0 # i = 0
b = 1 # i = 1
for x in range(2, n + 1):
result = a + b
a = b
b = result
return result
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_zeroth_fibonacci(self):
actual = fib(0)
expected = 0
self.assertEqual(actual, expected)
def test_first_fibonacci(self):
actual = fib(1)
expected = 1
self.assertEqual(actual, expected)
def test_second_fibonacci(self):
actual = fib(2)
expected = 1
self.assertEqual(actual, expected)
def test_third_fibonacci(self):
actual = fib(3)
expected = 2
self.assertEqual(actual, expected)
def test_fifth_fibonacci(self):
actual = fib(5)
expected = 5
self.assertEqual(actual, expected)
def test_tenth_fibonacci(self):
actual = fib(10)
expected = 55
self.assertEqual(actual, expected)
def test_negative_fibonacci(self):
with self.assertRaises(Exception):
fib(-1)
unittest.main(verbosity=2)

View file

@ -0,0 +1,49 @@
from random import choice
from math import floor
# Applying Chapter 1 from "Algorithms to Live By", which describes optimal
# stopping problems. Technically this simulation is invalid because the
# `candidates` function takes a lower bound and an upper bound, which allows us
# to know the cardinal number of an individual candidates. The "look then leap"
# algorithm is ideal for no-information games - i.e. games when upper and lower
# bounds aren't known. The `look_then_leap/1` function is ignorant of this
# information, so it behaves as if in a no-information game. Strangely enough,
# this algorithm will pick the best candidate 37% of the time.
#
# Chapter 1 describes two algorithms:
# 1. Look-then-leap: ordinal numbers - i.e. no-information games. Look-then-leap
# finds the best candidate 37% of the time.
# 2. Threshold: cardinal numbers - i.e. where upper and lower bounds are
# known. The Threshold algorithm finds the best candidate ~55% of the time.
#
# All of this and more can be studied as "optimal stopping theory". This applies
# to finding a spouse, parking a car, picking an apartment in a city, and more.
# candidates :: Int -> Int -> Int -> [Int]
def candidates(lb, ub, ct):
xs = list(range(lb, ub + 1))
return [choice(xs) for _ in range(ct)]
# look_then_leap :: [Integer] -> Integer
def look_then_leap(candidates):
best = candidates[0]
seen_ct = 1
ignore_ct = floor(len(candidates) * 0.37)
for x in candidates[1:]:
if ignore_ct > 0:
ignore_ct -= 1
best = max(best, x)
else:
if x > best:
print('Choosing the {} candidate.'.format(seen_ct))
return x
seen_ct += 1
print('You may have waited too long.')
return candidates[-1]
candidates = candidates(1, 100, 100)
print(candidates)
print(look_then_leap(candidates))

View file

@ -0,0 +1,83 @@
import unittest
################################################################################
# Answer
################################################################################
class Node(object):
def __init__(self, value, children=set()):
self.value = value
self.children = children
# treeify :: Char -> Set(Char) -> Node(Char)
def treeify(x, xs):
return Node(x, [treeify(c, xs - {c}) for c in xs])
# dft :: Node(Char) -> [String]
def dft(node):
result = []
s = []
s.append(('', node))
while s:
p, n = s.pop()
p += str(n.value)
if not n.children:
result.append(p)
else:
for c in n.children:
s.append((p, c))
return result
# main :: String -> Set(String)
def get_permutations(xs):
if xs == '':
return set([''])
ys = set(xs)
trees = []
for y in ys:
trees.append(treeify(y, ys - {y}))
result = set()
for t in trees:
for d in dft(t):
result.add(d)
return result
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_empty_string(self):
actual = get_permutations('')
expected = set([''])
self.assertEqual(actual, expected)
def test_one_character_string(self):
actual = get_permutations('a')
expected = set(['a'])
self.assertEqual(actual, expected)
def test_two_character_string(self):
actual = get_permutations('ab')
expected = set(['ab', 'ba'])
self.assertEqual(actual, expected)
def test_three_character_string(self):
actual = get_permutations('abc')
expected = set(['abc', 'acb', 'bac', 'bca', 'cab', 'cba'])
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,49 @@
from collections import Counter
import unittest
################################################################################
# Impl
################################################################################
# palindromifiable :: String -> Boolean
def has_palindrome_permutation(x):
bag = Counter(x)
odd_entries_ct = 0
for _, y in bag.items():
if y % 2 != 0:
odd_entries_ct += 1
return odd_entries_ct in {0, 1}
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_permutation_with_odd_number_of_chars(self):
result = has_palindrome_permutation('aabcbcd')
self.assertTrue(result)
def test_permutation_with_even_number_of_chars(self):
result = has_palindrome_permutation('aabccbdd')
self.assertTrue(result)
def test_no_permutation_with_odd_number_of_chars(self):
result = has_palindrome_permutation('aabcd')
self.assertFalse(result)
def test_no_permutation_with_even_number_of_chars(self):
result = has_palindrome_permutation('aabbcd')
self.assertFalse(result)
def test_empty_string(self):
result = has_palindrome_permutation('')
self.assertTrue(result)
def test_one_character_string(self):
result = has_palindrome_permutation('a')
self.assertTrue(result)
unittest.main(verbosity=2)

View file

@ -0,0 +1,55 @@
class Node(object):
# ctor :: a -> [a] -> Node(a)
def __init__(self, value, children=[]):
self.value = value
self.children = children
# is_leaf :: Node(a) -> Boolean
def is_leaf(node):
return len(node.children) == 0
# enumerate :: Node(a) -> Set(List(a))
def enumerate(node):
current = []
result = []
q = []
q.append(node)
while q:
x = q.pop()
print(x.value)
for c in x.children:
q.append(c)
current.append(x.value)
print(current)
if is_leaf(x):
result.append(current)
print("Reseting current")
current = []
return result
node = Node('root', [
Node('a', [
Node('b', [Node('c')]),
Node('c', [Node('b')]),
]),
Node('b', [
Node('a', [Node('c')]),
Node('c', [Node('a')]),
]),
Node('c', [
Node('a', [Node('b')]),
Node('b', [Node('a')]),
])
])
print('----------')
print(enumerate(node))

View file

@ -0,0 +1,9 @@
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.RandomState(10) # deterministic random data
a = np.hstack((rng.normal(size=1000), rng.normal(loc=5, scale=2, size=1000)))
_ = plt.hist(a, bins='auto') # arguments are passed to np.histogram
plt.title("Histogram with 'auto' bins")
Text(0.5, 1.0, "Histogram with 'auto' bins")
plt.show()

View file

@ -0,0 +1,68 @@
import unittest
################################################################################
# Solution
################################################################################
# f :: [Int] -> [Int]
def get_products_of_all_ints_except_at_index(xs):
if len(xs) in {0, 1}:
raise Exception
ct = len(xs)
lefts = [1] * ct
rights = [1] * ct
result = []
for i in range(1, ct):
lefts[i] = lefts[i - 1] * xs[i - 1]
for i in range(ct - 2, -1, -1):
rights[i] = rights[i + 1] * xs[i + 1]
return [lefts[i] * rights[i] for i in range(ct)]
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_small_list(self):
actual = get_products_of_all_ints_except_at_index([1, 2, 3])
expected = [6, 3, 2]
self.assertEqual(actual, expected)
def test_longer_list(self):
actual = get_products_of_all_ints_except_at_index([8, 2, 4, 3, 1, 5])
expected = [120, 480, 240, 320, 960, 192]
self.assertEqual(actual, expected)
def test_list_has_one_zero(self):
actual = get_products_of_all_ints_except_at_index([6, 2, 0, 3])
expected = [0, 0, 36, 0]
self.assertEqual(actual, expected)
def test_list_has_two_zeros(self):
actual = get_products_of_all_ints_except_at_index([4, 0, 9, 1, 0])
expected = [0, 0, 0, 0, 0]
self.assertEqual(actual, expected)
def test_one_negative_number(self):
actual = get_products_of_all_ints_except_at_index([-3, 8, 4])
expected = [32, -12, -24]
self.assertEqual(actual, expected)
def test_all_negative_numbers(self):
actual = get_products_of_all_ints_except_at_index([-7, -1, -4, -2])
expected = [-8, -56, -14, -28]
self.assertEqual(actual, expected)
def test_error_with_empty_list(self):
with self.assertRaises(Exception):
get_products_of_all_ints_except_at_index([])
def test_error_with_one_number(self):
with self.assertRaises(Exception):
get_products_of_all_ints_except_at_index([1])
unittest.main(verbosity=2)

View file

@ -0,0 +1,66 @@
import unittest
################################################################################
# Solution
################################################################################
class QueueTwoStacks(object):
def __init__(self):
self.a = []
self.b = []
def enqueue(self, x):
self.a.append(x)
def dequeue(self):
if self.b:
return self.b.pop()
else:
while self.a:
self.b.append(self.a.pop())
return self.dequeue()
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_basic_queue_operations(self):
queue = QueueTwoStacks()
queue.enqueue(1)
queue.enqueue(2)
queue.enqueue(3)
actual = queue.dequeue()
expected = 1
self.assertEqual(actual, expected)
actual = queue.dequeue()
expected = 2
self.assertEqual(actual, expected)
queue.enqueue(4)
actual = queue.dequeue()
expected = 3
self.assertEqual(actual, expected)
actual = queue.dequeue()
expected = 4
self.assertEqual(actual, expected)
def test_error_when_dequeue_from_new_queue(self):
queue = QueueTwoStacks()
with self.assertRaises(Exception):
queue.dequeue()
def test_error_when_dequeue_from_empty_queue(self):
queue = QueueTwoStacks()
queue.enqueue(1)
queue.enqueue(2)
actual = queue.dequeue()
expected = 1
self.assertEqual(actual, expected)
actual = queue.dequeue()
expected = 2
self.assertEqual(actual, expected)
with self.assertRaises(Exception):
queue.dequeue()
unittest.main(verbosity=2)

View file

@ -0,0 +1,246 @@
import unittest
################################################################################
# Solution
################################################################################
# bottom :: Rectangle -> Int
def bottom(x):
return x.get('bottom_y')
# top :: Rectangle -> Int
def top(x):
return bottom(x) + x.get('height')
# left :: Rectangle -> Int
def left(x):
return x.get('left_x')
# right :: Rectangle -> Int
def right(x):
return left(x) + x.get('width')
# sort_highest :: Rectangle -> Rectangle -> (Rectangle, Rectangle)
def sort_highest(x, y):
if top(x) >= top(y):
return x, y
else:
return y, x
# sort_leftmost :: Rectangle -> Rectangle -> (Rectangle, Rectangle)
def sort_leftmost(x, y):
if left(x) <= left(y):
return x, y
else:
return y, x
# rectify :: Int -> Int -> Int -> Int -> Rectify
def rectify(top=None, bottom=None, left=None, right=None):
assert top >= bottom
assert left <= right
return {
'left_x': left,
'bottom_y': bottom,
'width': right - left,
'height': top - bottom,
}
# empty_rect :: Rectangle
def empty_rect():
return {
'left_x': None,
'bottom_y': None,
'width': None,
'height': None,
}
# find_rectangular_overlap :: Rectangle -> Rectangle -> Maybe(Rectangle)
def find_rectangular_overlap(x, y):
ha, hb = sort_highest(x, y)
la, lb = sort_leftmost(x, y)
if bottom(hb) <= top(hb) <= bottom(ha) <= top(ha):
return empty_rect()
if left(la) <= right(la) <= left(lb) <= right(lb):
return empty_rect()
# We should have an intersection here.
verts = [bottom(ha), top(ha), bottom(hb), top(hb)]
verts.sort()
horzs = [left(la), right(la), left(lb), right(lb)]
horzs.sort()
return rectify(top=verts[2],
bottom=verts[1],
left=horzs[1],
right=horzs[2])
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_overlap_along_both_axes(self):
rect1 = {
'left_x': 1,
'bottom_y': 1,
'width': 6,
'height': 3,
}
rect2 = {
'left_x': 5,
'bottom_y': 2,
'width': 3,
'height': 6,
}
expected = {
'left_x': 5,
'bottom_y': 2,
'width': 2,
'height': 2,
}
actual = find_rectangular_overlap(rect1, rect2)
self.assertEqual(actual, expected)
def test_one_rectangle_inside_another(self):
rect1 = {
'left_x': 1,
'bottom_y': 1,
'width': 6,
'height': 6,
}
rect2 = {
'left_x': 3,
'bottom_y': 3,
'width': 2,
'height': 2,
}
expected = {
'left_x': 3,
'bottom_y': 3,
'width': 2,
'height': 2,
}
actual = find_rectangular_overlap(rect1, rect2)
self.assertEqual(actual, expected)
def test_both_rectangles_the_same(self):
rect1 = {
'left_x': 2,
'bottom_y': 2,
'width': 4,
'height': 4,
}
rect2 = {
'left_x': 2,
'bottom_y': 2,
'width': 4,
'height': 4,
}
expected = {
'left_x': 2,
'bottom_y': 2,
'width': 4,
'height': 4,
}
actual = find_rectangular_overlap(rect1, rect2)
self.assertEqual(actual, expected)
def test_touch_on_horizontal_edge(self):
rect1 = {
'left_x': 1,
'bottom_y': 2,
'width': 3,
'height': 4,
}
rect2 = {
'left_x': 2,
'bottom_y': 6,
'width': 2,
'height': 2,
}
expected = {
'left_x': None,
'bottom_y': None,
'width': None,
'height': None,
}
actual = find_rectangular_overlap(rect1, rect2)
self.assertEqual(actual, expected)
def test_touch_on_vertical_edge(self):
rect1 = {
'left_x': 1,
'bottom_y': 2,
'width': 3,
'height': 4,
}
rect2 = {
'left_x': 4,
'bottom_y': 3,
'width': 2,
'height': 2,
}
expected = {
'left_x': None,
'bottom_y': None,
'width': None,
'height': None,
}
actual = find_rectangular_overlap(rect1, rect2)
self.assertEqual(actual, expected)
def test_touch_at_a_corner(self):
rect1 = {
'left_x': 1,
'bottom_y': 1,
'width': 2,
'height': 2,
}
rect2 = {
'left_x': 3,
'bottom_y': 3,
'width': 2,
'height': 2,
}
expected = {
'left_x': None,
'bottom_y': None,
'width': None,
'height': None,
}
actual = find_rectangular_overlap(rect1, rect2)
self.assertEqual(actual, expected)
def test_no_overlap(self):
rect1 = {
'left_x': 1,
'bottom_y': 1,
'width': 2,
'height': 2,
}
rect2 = {
'left_x': 4,
'bottom_y': 6,
'width': 3,
'height': 6,
}
expected = {
'left_x': None,
'bottom_y': None,
'width': None,
'height': None,
}
actual = find_rectangular_overlap(rect1, rect2)
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,37 @@
import unittest
################################################################################
# Implementation
################################################################################
# get_permutations :: String -> Set(String)
def get_permutations(string):
pass
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_empty_string(self):
actual = get_permutations('')
expected = set([''])
self.assertEqual(actual, expected)
def test_one_character_string(self):
actual = get_permutations('a')
expected = set(['a'])
self.assertEqual(actual, expected)
def test_two_character_string(self):
actual = get_permutations('ab')
expected = set(['ab', 'ba'])
self.assertEqual(actual, expected)
def test_three_character_string(self):
actual = get_permutations('abc')
expected = set(['abc', 'acb', 'bac', 'bca', 'cab', 'cba'])
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,79 @@
import unittest
################################################################################
# Solution
################################################################################
# reverse :: List(a) -> List(a)
def reverse(node):
curr = node
prev = None
while curr:
nxt = curr.next
curr.next = prev
prev = curr
curr = nxt
# Make sure to understand the spec! Debugging takes time. Rewriting takes
# time.
return prev
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
class LinkedListNode(object):
def __init__(self, value, next=None):
self.value = value
self.next = next
def get_values(self):
node = self
values = []
while node is not None:
values.append(node.value)
node = node.next
return values
def test_short_linked_list(self):
second = Test.LinkedListNode(2)
first = Test.LinkedListNode(1, second)
result = reverse(first)
self.assertIsNotNone(result)
actual = result.get_values()
expected = [2, 1]
self.assertEqual(actual, expected)
def test_long_linked_list(self):
sixth = Test.LinkedListNode(6)
fifth = Test.LinkedListNode(5, sixth)
fourth = Test.LinkedListNode(4, fifth)
third = Test.LinkedListNode(3, fourth)
second = Test.LinkedListNode(2, third)
first = Test.LinkedListNode(1, second)
result = reverse(first)
self.assertIsNotNone(result)
actual = result.get_values()
expected = [6, 5, 4, 3, 2, 1]
self.assertEqual(actual, expected)
def test_one_element_linked_list(self):
first = Test.LinkedListNode(1)
result = reverse(first)
self.assertIsNotNone(result)
actual = result.get_values()
expected = [1]
self.assertEqual(actual, expected)
def test_empty_linked_list(self):
result = reverse(None)
self.assertIsNone(result)
unittest.main(verbosity=2)

View file

@ -0,0 +1,181 @@
from collections import deque
import unittest
################################################################################
# Solution
################################################################################
def rev(xs, i, j):
"""Reverse xs in place from [i, j]"""
while i < j:
xs[i], xs[j] = xs[j], xs[i]
i += 1
j -= 1
def rotate(xs, n, i=None, j=None):
"""Mutably rotates list, xs, n times. Positive n values rotate right while
negative n values rotate left. Rotate within window [i, j]."""
i = i or 0
j = j or len(xs) - 1
ct = j - i
if n < 0:
n = abs(n)
p = i + n - 1
rev(xs, i, p)
rev(xs, p + 1, j)
rev(xs, i, j)
else:
p = j - (n - 1)
rev(xs, p, j)
rev(xs, i, p - 1)
rev(xs, i, j)
return xs
def rev_words(xs, i, j):
if j + 1 == len(xs):
return 0
while j + 1 < len(xs):
while j + 1 < len(xs) and xs[j + 1] != ' ':
j += 1
rev(xs, i, j)
j += 2
i = j
return 0
def reverse_words(xs):
# first reverse everything
rev(xs, 0, len(xs) - 1)
return rev_words(xs, 0, 0)
def reverse_words_bak(xs, i=None, j=None):
i = i or 0
j = j or len(xs) - 1
w0, w1 = [], []
if i >= j:
return 0
pi = i
while pi < len(xs) and xs[pi] != ' ':
w0.append(xs[pi])
pi += 1
if pi == len(xs):
return 0
pj = j
while xs[pj] != ' ':
w1.append(xs[pj])
pj -= 1
d = len(w0) - len(w1)
rotate(xs, -1 * d, i, j)
for k in range(len(w1)):
xs[i + k] = w1[len(w1) - 1 - k]
for k in range(len(w0)):
xs[j - k] = w0[len(w0) - 1 - k]
while i != j and xs[i] != ' ' and xs[j] != ' ':
i += 1
j -= 1
if i == j:
return 0
elif xs[i] == ' ':
while j > 0 and xs[j] != ' ':
j -= 1
if j == 0:
return 0
elif xs[j] == ' ':
while i < len(xs) and xs[i] != ' ':
i += 1
if i == len(xs):
return 0
return reverse_words(xs, i + 1, j - 1)
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_rev(self):
xs = [1, 2, 3, 4, 5]
rev(xs, 0, len(xs) - 1)
self.assertEqual(xs, [5, 4, 3, 2, 1])
def test_rotate(self):
ys = [1, 2, 3, 4, 5]
xs = ys[:]
self.assertEqual(rotate(xs, 1, 1, 3), [1, 4, 2, 3, 5])
xs = ys[:]
self.assertEqual(rotate(xs, -1, 1, 3), [1, 3, 4, 2, 5])
xs = ys[:]
self.assertEqual(rotate(xs, 1), [5, 1, 2, 3, 4])
xs = ys[:]
self.assertEqual(rotate(xs, -1), [2, 3, 4, 5, 1])
xs = ys[:]
self.assertEqual(rotate(xs, -2), [3, 4, 5, 1, 2])
xs = ys[:]
self.assertEqual(rotate(xs, -5), [1, 2, 3, 4, 5])
xs = ys[:]
self.assertEqual(rotate(xs, 5), [1, 2, 3, 4, 5])
xs = ys[:]
self.assertEqual(rotate(xs, 3), [3, 4, 5, 1, 2])
def test_one_word(self):
message = list('vault')
reverse_words(message)
expected = list('vault')
self.assertEqual(message, expected)
def test_two_words(self):
message = list('thief cake')
reverse_words(message)
expected = list('cake thief')
self.assertEqual(message, expected)
def test_three_words(self):
message = list('one another get')
reverse_words(message)
expected = list('get another one')
self.assertEqual(message, expected)
def test_multiple_words_same_length(self):
message = list('rat the ate cat the')
reverse_words(message)
expected = list('the cat ate the rat')
self.assertEqual(message, expected)
def test_multiple_words_different_lengths(self):
message = list('at rat house')
reverse_words(message)
expected = list('house rat at')
self.assertEqual(message, expected)
def test_multiple_words_different_lengths(self):
message = list('yummy is cake bundt chocolate')
reverse_words(message)
expected = list('chocolate bundt cake is yummy')
self.assertEqual(message, expected)
def test_empty_string(self):
message = list('')
reverse_words(message)
expected = list('')
self.assertEqual(message, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,179 @@
import unittest
from collections import deque
################################################################################
# Implementation
################################################################################
def is_leaf(node):
return node.left is None and node.right is None
def find_largest(node):
current = node
while current.right is not None:
current = current.right
return current.value
def find_second_largest(node):
history = deque()
current = node
while current.right:
history.append(current)
current = current.right
if current.left:
return find_largest(current.left)
elif history:
return history.pop().value
else:
raise TypeError
def find_second_largest_backup(node):
history = deque()
current = node
# traverse -> largest
while current.right:
history.append(current)
current = current.right
if current.left:
return find_largest(current.left)
elif history:
return history.pop().value
else:
raise ArgumentError
# Write a iterative version to avoid consuming memory with the call stack.
# Commenting out the recursive code for now.
def find_second_largest_backup(node):
if node.left is None and node.right is None:
raise ArgumentError
elif node.right is None and is_leaf(node.left):
return node.left.value
# recursion
# elif node.right is None:
# return find_largest(node.left)
# iterative version
elif node.right is None:
current = node.left
while current.right is not None:
current = current.right
return current.value
# recursion
# TODO: Remove recursion from here.
elif not is_leaf(node.right):
return find_second_largest(node.right)
# could do an else here, but let's be more assertive.
elif is_leaf(node.right):
return node.value
else:
raise ArgumentError
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
class BinaryTreeNode(object):
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def insert_left(self, value):
self.left = Test.BinaryTreeNode(value)
return self.left
def insert_right(self, value):
self.right = Test.BinaryTreeNode(value)
return self.right
def test_full_tree(self):
tree = Test.BinaryTreeNode(50)
left = tree.insert_left(30)
right = tree.insert_right(70)
left.insert_left(10)
left.insert_right(40)
right.insert_left(60)
right.insert_right(80)
actual = find_second_largest(tree)
expected = 70
self.assertEqual(actual, expected)
def test_largest_has_a_left_child(self):
tree = Test.BinaryTreeNode(50)
left = tree.insert_left(30)
right = tree.insert_right(70)
left.insert_left(10)
left.insert_right(40)
right.insert_left(60)
actual = find_second_largest(tree)
expected = 60
self.assertEqual(actual, expected)
def test_largest_has_a_left_subtree(self):
tree = Test.BinaryTreeNode(50)
left = tree.insert_left(30)
right = tree.insert_right(70)
left.insert_left(10)
left.insert_right(40)
right_left = right.insert_left(60)
right_left_left = right_left.insert_left(55)
right_left.insert_right(65)
right_left_left.insert_right(58)
actual = find_second_largest(tree)
expected = 65
self.assertEqual(actual, expected)
def test_second_largest_is_root_node(self):
tree = Test.BinaryTreeNode(50)
left = tree.insert_left(30)
tree.insert_right(70)
left.insert_left(10)
left.insert_right(40)
actual = find_second_largest(tree)
expected = 50
self.assertEqual(actual, expected)
def test_descending_linked_list(self):
tree = Test.BinaryTreeNode(50)
left = tree.insert_left(40)
left_left = left.insert_left(30)
left_left_left = left_left.insert_left(20)
left_left_left.insert_left(10)
actual = find_second_largest(tree)
expected = 40
self.assertEqual(actual, expected)
def test_ascending_linked_list(self):
tree = Test.BinaryTreeNode(50)
right = tree.insert_right(60)
right_right = right.insert_right(70)
right_right.insert_right(80)
actual = find_second_largest(tree)
expected = 70
self.assertEqual(actual, expected)
def test_error_when_tree_has_one_node(self):
tree = Test.BinaryTreeNode(50)
with self.assertRaises(Exception):
find_second_largest(tree)
def test_error_when_tree_is_empty(self):
with self.assertRaises(Exception):
find_second_largest(None)
unittest.main(verbosity=2)

View file

@ -0,0 +1,94 @@
from heapq import heappush, heappop
from collections import deque
from fixtures import weighted_graph, expanded_weights_graph
# UnweightedGraph(a) :: Map(a, Set(a))
# WeightedGraph(a) :: Map(a, Set(a))
# shortest_path_dijkstra :: Vertex -> Vertex -> WeightedGraph(Vertex)
def shortest_path_dijkstra(a, b, g):
q = []
seen = set()
heappush(q, (0, a, [a]))
while q:
w0, v0, path = heappop(q)
if v0 in seen:
continue
elif v0 == b:
return w0, path
for w1, v1 in g.get(v0):
heappush(q, (w0 + w1, v1, path + [v1]))
seen.add(v0)
return 'weighted', 'pizza'
# expand_edge :: Vertex -> (Weight, Vertex) -> Map(Vertex, [Vertex])
def expand_edge(v0, wv):
w, v1 = wv
assert w > 1
result = {v0: ['{}-{}'.format(v1, 1)]}
for x in range(w - 2):
result['{}-{}'.format(v1, x + 1)] = ['{}-{}'.format(v1, x + 2)]
result['{}-{}'.format(v1, w - 1)] = [v1]
return result
# expand_weights :: Vertex -> WeightedGraph(Vertex) -> UnweightedGraph(Vertex)
def expand_weights(v, g):
result = {}
q = deque()
seen = set()
q.append(v)
while q:
v = d.popleft()
if v in seen:
continue
x = expand_edge(v, g.get)
for w, v1 in g.get(v):
if w > 1:
ws = expand_edge(v, (w, v1))
result = {**result, **ws}
q.append(v)
pass
# shortest_path_inject :: Vertex -> Vertex -> WeightedGraph(Vertex)
def shortest_path_inject(a, b, g):
q = deque()
seen = set()
q.append((a, [a]))
while q:
v0, path = q.popleft()
if v0 == 'dummy':
continue
elif v0 in seen:
continue
elif v0 == b:
return len(path), path
for _, v1 in g.get(v0):
q.append((v1, path + [v1]))
seen.add(v0)
continue
return None, None
print(expand_edge('a', (4, 'b')))
print(expand_edge('a', (5, 'e')))
assert expand_weights('a', weighted_graph) == expanded_weights_graph
# a = 'a'
# b = 'd'
# w, x = shortest_path_dijkstra(a, b, weighted_graph)
# w1, x1 = shortest_path_inject(a, b, weighted_graph)
# print("[dijkstra] Shortest path from {} to {} is {} with weight {}".format(
# a, b, x, w))
# print("[injection] Shortest path from {} to {} is {} with weight {}".format(
# a, b, x1, w1))

View file

@ -0,0 +1,34 @@
import random
def get_random(floor, ceiling):
return random.randrange(floor, ceiling + 1)
# shuffle_in_place :: [a] -> IO ()
def shuffle_in_place(xs):
"""Fisher-Yates algorithm. Notice that shuffling here is the same as
selecting a random permutation of the input set, `xs`."""
n = len(xs) - 1
for i in range(len(xs)):
r = get_random(i, n)
xs[i], xs[r] = xs[r], xs[i]
return xs
# shuffle :: [a] -> [a]
def shuffle_not_in_place(xs):
result = []
while xs:
i = get_random(0, len(xs) - 1)
x = xs.pop(i)
result.append(x)
return result
xs = [x for x in range(9)]
print(xs)
# print(shuffle_not_in_place(xs))
print(shuffle_in_place(xs[:]))

View file

@ -0,0 +1,22 @@
# swap :: Int -> Int -> [Char] -> IO ()
def swap(ia, iz, xs):
# handle swap when ia == iz
assert ia <= iz
xs[ia], xs[iz] = xs[iz], xs[ia]
# reverse :: [Char] -> IO ()
def reverse(xs):
ia = 0
iz = len(xs) - 1
while ia <= iz:
swap(ia, iz, xs)
ia += 1
iz -= 1
x = list("superduperpooper")
reverse(x)
print(x)
print("Tests pass")

View file

@ -0,0 +1,84 @@
import unittest
################################################################################
# Solution
################################################################################
class TempTracker(object):
def __init__(self):
# min / max
self.min = None
self.max = None
# mean
self.sum = 0
self.num = 0
# mode
self.nums = [0] * 111
self.mode_num = 0
self.mode = None
def insert(self, x):
# min / max
if not self.min or x < self.min:
self.min = x
if not self.max or x > self.max:
self.max = x
# mean
self.sum += x
self.num += 1
# mode
self.nums[x] += 1
if self.nums[x] >= self.mode_num:
self.mode_num = self.nums[x]
self.mode = x
def get_max(self):
return self.max
def get_min(self):
return self.min
def get_mean(self):
return self.sum / self.num
def get_mode(self):
return self.mode
# Tests
class Test(unittest.TestCase):
def test_tracker_usage(self):
tracker = TempTracker()
tracker.insert(50)
msg = 'failed on first temp recorded'
self.assertEqual(tracker.get_max(), 50, msg='max ' + msg)
self.assertEqual(tracker.get_min(), 50, msg='min ' + msg)
self.assertEqual(tracker.get_mean(), 50.0, msg='mean ' + msg)
self.assertEqual(tracker.get_mode(), 50, msg='mode ' + msg)
tracker.insert(80)
msg = 'failed on higher temp recorded'
self.assertEqual(tracker.get_max(), 80, msg='max ' + msg)
self.assertEqual(tracker.get_min(), 50, msg='min ' + msg)
self.assertEqual(tracker.get_mean(), 65.0, msg='mean ' + msg)
self.assertIn(tracker.get_mode(), [50, 80], msg='mode ' + msg)
tracker.insert(80)
msg = 'failed on third temp recorded'
self.assertEqual(tracker.get_max(), 80, msg='max ' + msg)
self.assertEqual(tracker.get_min(), 50, msg='min ' + msg)
self.assertEqual(tracker.get_mean(), 70.0, msg='mean ' + msg)
self.assertEqual(tracker.get_mode(), 80, msg='mode ' + msg)
tracker.insert(30)
msg = 'failed on lower temp recorded'
self.assertEqual(tracker.get_max(), 80, msg='max ' + msg)
self.assertEqual(tracker.get_min(), 30, msg='min ' + msg)
self.assertEqual(tracker.get_mean(), 60.0, msg='mean ' + msg)
self.assertEqual(tracker.get_mode(), 80, msg='mode ' + msg)
unittest.main(verbosity=2)

View file

@ -0,0 +1 @@
hello

View file

@ -0,0 +1,25 @@
from collections import deque
# list:
# array:
# vector:
# bit-{array,vector}:
def sort(xs, highest):
v = [0] * (highest + 1)
result = deque()
for x in xs:
v[x] += 1
for i, x in enumerate(v):
if x > 0:
result.appendleft(i)
return list(result)
assert sort([37, 89, 41, 100, 65, 91, 53],
100) == [100, 91, 89, 65, 53, 41, 37]
print("Tests pass!")

View file

@ -0,0 +1,31 @@
from fixtures import unweighted_digraph
from collections import deque
# vertices_no_in_edges :: UnweightedDigraph -> Set(Vertex)
def vertices_no_in_edges(g):
"""Return the vertices in graph `g` with no in-edges."""
result = set()
vertices = set(g.keys())
for neighbors in g.values():
result = result.union(neighbors)
return vertices ^ result
# topo_sort :: UnweightedDigraph -> List(Vertex)
def topo_sort(g):
q = deque()
seen = set()
result = []
for x in vertices_no_in_edges(g):
q.append(x)
while q:
vertex = q.popleft()
if vertex in seen:
continue
result.append(vertex)
neighbors = g.get(vertex)
for x in g.get(vertex):
q.append(x)
seen.add(vertex)
return result
print(topo_sort(unweighted_digraph))

View file

@ -0,0 +1,38 @@
class Node(object):
def __init__(self, value, children=[]):
self.value = value
self.children = children
################################################################################
# Solution
################################################################################
def trip_time(node):
s = []
result = 0
s.append((node.value, node))
while s:
p, node = s.pop()
if not node.children:
result = max(result, p)
for x in node.children:
s.append((p + x.value, x))
return result
################################################################################
# Tests
################################################################################
tree = Node(
0,
children=[
Node(5, children=[Node(6)]),
Node(2, children=[
Node(6),
Node(10),
]),
Node(3, children=[Node(2, children=[Node(11)])]),
])
assert trip_time(tree) == 16
print("Tests pass!")

View file

@ -0,0 +1,33 @@
import unittest
################################################################################
# Solution
################################################################################
# find_repeat :: [Int] -> Int
def find_repeat(xs):
n = len(xs) - 1
return sum(xs) - ((n**2 + n) / 2)
################################################################################
# Tests
################################################################################
class Test(unittest.TestCase):
def test_short_list(self):
actual = find_repeat([1, 2, 1])
expected = 1
self.assertEqual(actual, expected)
def test_medium_list(self):
actual = find_repeat([4, 1, 3, 4, 2])
expected = 4
self.assertEqual(actual, expected)
def test_long_list(self):
actual = find_repeat([1, 5, 9, 7, 2, 6, 3, 8, 2, 4])
expected = 2
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,123 @@
import unittest
from collections import deque
def is_balanced(node):
q, seen, ds = deque(), set(), set()
q.append((0, node))
while q:
d, node = q.popleft()
l, r = node.left, node.right
seen.add(node)
if not l and not r:
if d not in ds and len(ds) == 2:
return False
else:
ds.add(d)
if l and l not in seen:
q.append((d + 1, l))
if r and r not in seen:
q.append((d + 1, r))
return max(ds) - min(ds) <= 1
# Tests
class Test(unittest.TestCase):
class BinaryTreeNode(object):
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def insert_left(self, value):
self.left = Test.BinaryTreeNode(value)
return self.left
def insert_right(self, value):
self.right = Test.BinaryTreeNode(value)
return self.right
def test_full_tree(self):
tree = Test.BinaryTreeNode(5)
left = tree.insert_left(8)
right = tree.insert_right(6)
left.insert_left(1)
left.insert_right(2)
right.insert_left(3)
right.insert_right(4)
result = is_balanced(tree)
self.assertTrue(result)
def test_both_leaves_at_the_same_depth(self):
tree = Test.BinaryTreeNode(3)
left = tree.insert_left(4)
right = tree.insert_right(2)
left.insert_left(1)
right.insert_right(9)
result = is_balanced(tree)
self.assertTrue(result)
def test_leaf_heights_differ_by_one(self):
tree = Test.BinaryTreeNode(6)
left = tree.insert_left(1)
right = tree.insert_right(0)
right.insert_right(7)
result = is_balanced(tree)
self.assertTrue(result)
def test_leaf_heights_differ_by_two(self):
tree = Test.BinaryTreeNode(6)
left = tree.insert_left(1)
right = tree.insert_right(0)
right_right = right.insert_right(7)
right_right.insert_right(8)
result = is_balanced(tree)
self.assertFalse(result)
def test_three_leaves_total(self):
tree = Test.BinaryTreeNode(1)
left = tree.insert_left(5)
right = tree.insert_right(9)
right.insert_left(8)
right.insert_right(5)
result = is_balanced(tree)
self.assertTrue(result)
def test_both_subtrees_superbalanced(self):
tree = Test.BinaryTreeNode(1)
left = tree.insert_left(5)
right = tree.insert_right(9)
right_left = right.insert_left(8)
right.insert_right(5)
right_left.insert_left(7)
result = is_balanced(tree)
self.assertFalse(result)
def test_both_subtrees_superbalanced_two(self):
tree = Test.BinaryTreeNode(1)
left = tree.insert_left(2)
right = tree.insert_right(4)
left.insert_left(3)
left_right = left.insert_right(7)
left_right.insert_right(8)
right_right = right.insert_right(5)
right_right_right = right_right.insert_right(6)
right_right_right.insert_right(9)
result = is_balanced(tree)
self.assertFalse(result)
def test_only_one_node(self):
tree = Test.BinaryTreeNode(1)
result = is_balanced(tree)
self.assertTrue(result)
def test_linked_list_tree(self):
tree = Test.BinaryTreeNode(1)
right = tree.insert_right(2)
right_right = right.insert_right(3)
right_right.insert_right(4)
result = is_balanced(tree)
self.assertTrue(result)
unittest.main(verbosity=2)

View file

@ -0,0 +1,26 @@
# Doing a practice implementation of Dijkstra's algorithm: a priority-first
# search.
from heapq import heappush, heappop
class Node(object):
def __init__(self, value, children):
self.value = value
self.children = children
def shortest_path(a, b):
"""Return the shortest path from `a` to `b`."""
q = []
seen = set()
heappush((a.value, a, [a]), q)
while q:
d, node, path = heappop(q)
if node == b:
return path
seen.add(node)
for child in node.children:
if child not in seen:
heappush((d + child.value, child, path + [child]), q)
raise Exception("Path between nodes A and B does not exist.")

View file

@ -0,0 +1,6 @@
* Sorting
** Merge: O(n*log(n))
** Heap: O(n*log(n))
** Insertion: O(n^2)
** Quick: O(n^2)
** Bubble: O(n^2)

View file

@ -0,0 +1,55 @@
import unittest
from math import floor
def midpoint(a, b):
return a + floor((b - a) / 2)
def do_find_rotation_point(a, b, xs):
i = midpoint(a, b)
count = b - a + 1
if count == 2:
if xs[a] > xs[b]:
return b
else:
return -1
if i in {a, b}:
return i
if xs[a] < xs[i]:
return do_find_rotation_point(i, b, xs)
else:
return do_find_rotation_point(a, i, xs)
def find_rotation_point(xs):
return do_find_rotation_point(0, len(xs) - 1, xs)
# Tests
class Test(unittest.TestCase):
def test_small_list(self):
actual = find_rotation_point(['cape', 'cake'])
expected = 1
self.assertEqual(actual, expected)
def test_medium_list(self):
actual = find_rotation_point(
['grape', 'orange', 'plum', 'radish', 'apple'])
expected = 4
self.assertEqual(actual, expected)
def test_large_list(self):
actual = find_rotation_point([
'ptolemaic', 'retrograde', 'supplant', 'undulate', 'xenoepist',
'asymptote', 'babka', 'banoffee', 'engender', 'karpatka',
'othellolagkage'
])
expected = 5
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,51 @@
import unittest
def can_two_movies_fill_flight(xs, t):
seeking = set()
for x in xs:
if x in seeking:
return True
else:
seeking.add(t - x)
return False
# Tests
class Test(unittest.TestCase):
def test_short_flight(self):
result = can_two_movies_fill_flight([2, 4], 1)
self.assertFalse(result)
def test_long_flight(self):
result = can_two_movies_fill_flight([2, 4], 6)
self.assertTrue(result)
def test_one_movie_half_flight_length(self):
result = can_two_movies_fill_flight([3, 8], 6)
self.assertFalse(result)
def test_two_movies_half_flight_length(self):
result = can_two_movies_fill_flight([3, 8, 3], 6)
self.assertTrue(result)
def test_lots_of_possible_pairs(self):
result = can_two_movies_fill_flight([1, 2, 3, 4, 5, 6], 7)
self.assertTrue(result)
def test_not_using_first_movie(self):
result = can_two_movies_fill_flight([4, 3, 2], 5)
self.assertTrue(result)
def test_only_one_movie(self):
result = can_two_movies_fill_flight([6], 6)
self.assertFalse(result)
def test_no_movies(self):
result = can_two_movies_fill_flight([], 2)
self.assertFalse(result)
unittest.main(verbosity=2)

View file

@ -0,0 +1,64 @@
import unittest
def kth_to_last_node(k, x):
a, b = x, x
if k == 0:
raise Exception('Value of 0 for k is not supported')
for _ in range(k - 1):
if not a.next:
raise Exception('Value of {} for k is too large'.format(k))
a = a.next
while a.next:
a, b = a.next, b.next
return b
class Test(unittest.TestCase):
class LinkedListNode(object):
def __init__(self, value, next=None):
self.value = value
self.next = next
def get_values(self):
node = self
values = []
while node is not None:
values.append(node.value)
node = node.next
return values
def setUp(self):
self.fourth = Test.LinkedListNode(4)
self.third = Test.LinkedListNode(3, self.fourth)
self.second = Test.LinkedListNode(2, self.third)
self.first = Test.LinkedListNode(1, self.second)
def test_first_to_last_node(self):
actual = kth_to_last_node(1, self.first)
expected = self.fourth
self.assertEqual(actual, expected)
def test_second_to_last_node(self):
actual = kth_to_last_node(2, self.first)
expected = self.third
self.assertEqual(actual, expected)
def test_first_node(self):
actual = kth_to_last_node(4, self.first)
expected = self.first
self.assertEqual(actual, expected)
def test_k_greater_than_linked_list_length(self):
with self.assertRaises(Exception):
kth_to_last_node(5, self.first)
def test_k_is_zero(self):
with self.assertRaises(Exception):
kth_to_last_node(0, self.first)
unittest.main(verbosity=2)

View file

@ -0,0 +1,59 @@
import unittest
def merge_ranges(xs):
xs.sort()
result = [xs[0]]
for curr in xs[1:]:
a, z = result[-1]
if z >= curr[0]:
result[-1] = (a, max(z, curr[1]))
else:
result.append(curr)
return result
# Tests
class Test(unittest.TestCase):
def test_meetings_overlap(self):
actual = merge_ranges([(1, 3), (2, 4)])
expected = [(1, 4)]
self.assertEqual(actual, expected)
def test_meetings_touch(self):
actual = merge_ranges([(5, 6), (6, 8)])
expected = [(5, 8)]
self.assertEqual(actual, expected)
def test_meeting_contains_other_meeting(self):
actual = merge_ranges([(1, 8), (2, 5)])
expected = [(1, 8)]
self.assertEqual(actual, expected)
def test_meetings_stay_separate(self):
actual = merge_ranges([(1, 3), (4, 8)])
expected = [(1, 3), (4, 8)]
self.assertEqual(actual, expected)
def test_multiple_merged_meetings(self):
actual = merge_ranges([(1, 4), (2, 5), (5, 8)])
expected = [(1, 8)]
self.assertEqual(actual, expected)
def test_meetings_not_sorted(self):
actual = merge_ranges([(5, 8), (1, 4), (6, 8)])
expected = [(1, 4), (5, 8)]
self.assertEqual(actual, expected)
def test_one_long_meeting_contains_smaller_meetings(self):
actual = merge_ranges([(1, 10), (2, 5), (6, 8), (9, 10), (10, 12)])
expected = [(1, 12)]
self.assertEqual(actual, expected)
def test_sample_input(self):
actual = merge_ranges([(0, 1), (3, 5), (4, 8), (10, 12), (9, 10)])
expected = [(0, 1), (3, 8), (9, 12)]
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,56 @@
import unittest
from itertools import permutations
class Node(object):
def __init__(self, x):
self.value = x
self.children = []
def make_tree(c, xs):
root = Node(c)
for x in xs:
root.children.append(make_tree(x, xs - {x}))
return root
def get_permutations(xs):
xs = set(xs)
root = make_tree("", xs)
q, perms = [], set()
q.append(("", root))
while q:
c, node = q.pop()
if not node.children:
perms.add(c)
else:
for child in node.children:
q.append((c + child.value, child))
return perms
# Tests
class Test(unittest.TestCase):
def test_empty_string(self):
actual = get_permutations('')
expected = set([''])
self.assertEqual(actual, expected)
def test_one_character_string(self):
actual = get_permutations('a')
expected = set(['a'])
self.assertEqual(actual, expected)
def test_two_character_string(self):
actual = get_permutations('ab')
expected = set(['ab', 'ba'])
self.assertEqual(actual, expected)
def test_three_character_string(self):
actual = get_permutations('abc')
expected = set(['abc', 'acb', 'bac', 'bca', 'cab', 'cba'])
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,74 @@
import unittest
def reverse(node):
prev = None
next = None
curr = node
while curr:
next = curr.next
curr.next = prev
prev = curr
curr = next
return prev
# Tests
class Test(unittest.TestCase):
class LinkedListNode(object):
def __init__(self, value, next=None):
self.value = value
self.next = next
def get_values(self):
node = self
values = []
while node is not None:
values.append(node.value)
node = node.next
return values
def test_short_linked_list(self):
second = Test.LinkedListNode(2)
first = Test.LinkedListNode(1, second)
result = reverse(first)
self.assertIsNotNone(result)
actual = result.get_values()
expected = [2, 1]
self.assertEqual(actual, expected)
def test_long_linked_list(self):
sixth = Test.LinkedListNode(6)
fifth = Test.LinkedListNode(5, sixth)
fourth = Test.LinkedListNode(4, fifth)
third = Test.LinkedListNode(3, fourth)
second = Test.LinkedListNode(2, third)
first = Test.LinkedListNode(1, second)
result = reverse(first)
self.assertIsNotNone(result)
actual = result.get_values()
expected = [6, 5, 4, 3, 2, 1]
self.assertEqual(actual, expected)
def test_one_element_linked_list(self):
first = Test.LinkedListNode(1)
result = reverse(first)
self.assertIsNotNone(result)
actual = result.get_values()
expected = [1]
self.assertEqual(actual, expected)
def test_empty_linked_list(self):
result = reverse(None)
self.assertIsNone(result)
unittest.main(verbosity=2)

View file

@ -0,0 +1,51 @@
def get_max_profit(xs):
best_profit = xs[1] - xs[0]
lowest_buy = xs[0]
for x in xs[1:]:
best_profit = max(best_profit, x - lowest_buy)
lowest_buy = min(lowest_buy, x)
return best_profit
# Tests
import unittest
class Test(unittest.TestCase):
def test_price_goes_up_then_down(self):
actual = get_max_profit([1, 5, 3, 2])
expected = 4
self.assertEqual(actual, expected)
def test_price_goes_down_then_up(self):
actual = get_max_profit([7, 2, 8, 9])
expected = 7
self.assertEqual(actual, expected)
def test_price_goes_up_all_day(self):
actual = get_max_profit([1, 6, 7, 9])
expected = 8
self.assertEqual(actual, expected)
def test_price_goes_down_all_day(self):
actual = get_max_profit([9, 7, 4, 1])
expected = -2
self.assertEqual(actual, expected)
def test_price_stays_the_same_all_day(self):
actual = get_max_profit([1, 1, 1, 1])
expected = 0
self.assertEqual(actual, expected)
def test_error_with_empty_prices(self):
with self.assertRaises(Exception):
get_max_profit([])
def test_error_with_one_price(self):
with self.assertRaises(Exception):
get_max_profit([1])
unittest.main(verbosity=2)

View file

@ -0,0 +1,29 @@
import unittest
def find_repeat(xs):
n = max(xs)
expected_sum = (n + 1) * n / 2
actual_sum = sum(xs)
return actual_sum - expected_sum
# Tests
class Test(unittest.TestCase):
def test_short_list(self):
actual = find_repeat([1, 2, 1])
expected = 1
self.assertEqual(actual, expected)
def test_medium_list(self):
actual = find_repeat([4, 1, 3, 4, 2])
expected = 4
self.assertEqual(actual, expected)
def test_long_list(self):
actual = find_repeat([1, 5, 9, 7, 2, 6, 3, 8, 2, 4])
expected = 2
self.assertEqual(actual, expected)
unittest.main(verbosity=2)

View file

@ -0,0 +1,2 @@
source_up
eval "$(lorri direnv)"

View file

@ -0,0 +1,57 @@
import unittest
def delete_node(node):
if node.next:
node.value = node.next.value
node.next = node.next.next
else:
raise Exception(
"We cannot delete the last node in a linked list using this function"
)
# Tests
class Test(unittest.TestCase):
class LinkedListNode(object):
def __init__(self, value, next=None):
self.value = value
self.next = next
def get_values(self):
node = self
values = []
while node is not None:
values.append(node.value)
node = node.next
return values
def setUp(self):
self.fourth = Test.LinkedListNode(4)
self.third = Test.LinkedListNode(3, self.fourth)
self.second = Test.LinkedListNode(2, self.third)
self.first = Test.LinkedListNode(1, self.second)
def test_node_at_beginning(self):
delete_node(self.first)
actual = self.first.get_values()
expected = [2, 3, 4]
self.assertEqual(actual, expected)
def test_node_in_middle(self):
delete_node(self.second)
actual = self.first.get_values()
expected = [1, 3, 4]
self.assertEqual(actual, expected)
def test_node_at_end(self):
with self.assertRaises(Exception):
delete_node(self.fourth)
def test_one_node_in_list(self):
unique = Test.LinkedListNode(1)
with self.assertRaises(Exception):
delete_node(unique)
unittest.main(verbosity=2)

View file

@ -0,0 +1,104 @@
# Herein I'm practicing two-dimensional matrix traversals in all directions of
# which I can conceive:
# 0. T -> B; L -> R
# 1. T -> B; R -> L
# 2. B -> T; L -> R
# 3. B -> T; R -> L
#
# Commentary:
# When I think of matrices, I'm reminded of cartesian planes. I think of the
# cells as (X,Y) coordinates. This has been a pitfall for me because matrices
# are usually encoded in the opposite way. That is, to access a cell at the
# coordinates (X,Y) given a matrix M, you index M like this: M[Y][X]. To attempt
# to avoid this confusion, instead of saying X and Y, I will prefer saying
# "column" and "row".
#
# When traversing a matrix, you typically traverse vertically and then
# horizontally; in other words, the rows come first followed by the columns. As
# such, I'd like to refer to traversal orders as "top-to-bottom, left-to-right"
# rather than "left-to-right, top-to-bottom".
#
# These practices are all in an attempt to rewire my thinking.
# This is a list of matrices where the index of a matrix corresponds to the
# order in which it should be traversed to produce the sequence:
# [1,2,3,4,5,6,7,8,9].
boards = [[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[3, 2, 1], [6, 5, 4], [9, 8, 7]],
[[7, 8, 9], [4, 5, 6], [1, 2, 3]], [[9, 8, 7], [6, 5, 4], [3, 2, 1]]]
# T -> B; L -> R
board = boards[0]
result = []
for row in board:
for col in row:
result.append(col)
print(result)
# T -> B; R -> L
board = boards[1]
result = []
for row in board:
for col in reversed(row):
result.append(col)
print(result)
# B -> T; L -> R
board = boards[2]
result = []
for row in reversed(board):
for col in row:
result.append(col)
print(result)
# B -> T; R -> L
board = boards[3]
result = []
for row in reversed(board):
for col in reversed(row):
result.append(col)
print(result)
################################################################################
# Neighbors
################################################################################
import random
# Generate a matrix of size `rows` x `cols` where each cell contains an item
# randomly selected from `xs`.
def generate_board(rows, cols, xs):
result = []
for _ in range(rows):
row = []
for _ in range(cols):
row.append(random.choice(xs))
result.append(row)
return result
# Print the `board` to the screen.
def print_board(board):
print('\n'.join([' '.join(row) for row in board]))
board = generate_board(4, 5, ['R', 'G', 'B'])
print_board(board)
# Return all of the cells horizontally and vertically accessible from a starting
# cell at `row`, `col` in `board`.
def neighbors(row, col, board):
result = {'top': [], 'bottom': [], 'left': [], 'right': []}
for i in range(row - 1, -1, -1):
result['top'].append(board[i][col])
for i in range(row + 1, len(board)):
result['bottom'].append(board[i][col])
for i in range(col - 1, -1, -1):
result['left'].append(board[row][i])
for i in range(col + 1, len(board[0])):
result['right'].append(board[row][i])
return result
print(neighbors(1, 2, board))

View file

@ -0,0 +1,73 @@
{
"name": "deepmind-part-two",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
"make-error": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
"integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
"dev": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-support": {
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
"integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"ts-node": {
"version": "8.6.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.6.2.tgz",
"integrity": "sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg==",
"dev": true,
"requires": {
"arg": "^4.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"source-map-support": "^0.5.6",
"yn": "3.1.1"
}
},
"typescript": {
"version": "3.7.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz",
"integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==",
"dev": true
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true
}
}
}

View file

@ -0,0 +1,15 @@
{
"name": "deepmind-part-two",
"version": "1.0.0",
"description": "Practicing coding interview questions",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "William Carroll",
"license": "MIT",
"devDependencies": {
"ts-node": "^8.6.2",
"typescript": "^3.7.5"
}
}

View file

@ -0,0 +1,13 @@
// Reverse array of characters, `xs`, mutatively.
function reverse(xs: Array<string>) {
let i: number = 0;
let j: number = xs.length - 1;
while (i < j) {
let tmp = xs[i];
xs[i] = xs[j]
xs[j] = tmp
i += 1
j -= 1
}
}

View file

@ -0,0 +1,10 @@
{ pkgs ? import <nixpkgs> {}, ... }:
pkgs.mkShell {
buildInputs = with pkgs; [
nodejs
python3
go
goimports
];
}

View file

@ -0,0 +1,77 @@
* Array and string manipulation
** TODO Merging Meeting Times
** DONE Reverse String in Place
** TODO Reverse Words
** TODO Merge Sorted Arrays
** TODO Cafe Order Checker
* Hashing and hash tables
** TODO Inflight Entertainment
** TODO Permutation Palindrome
** TODO Word Cloud Data
** TODO Top Scores
* Greedy Algorithms
** TODO Apple Stocks
** TODO Highest Product of 3
** TODO Product of All Other Numbers
** TODO Cafe Order Checker
** TODO In-Place Shuffle
* Sorting, searching, and logarithms
** TODO Find Rotation Point
** TODO Find Repeat, Space Edition
** TODO Top Scores
** TODO Merging Meeting Times
* Trees and graphs
** TODO Balanced Binary Tree
** TODO Binary Search Tree Checker
** TODO 2nd Largest Item in a Binary Search Tree
** TODO Graph Coloring
** TODO MeshMessage
** TODO Find Repeat, Space Edition BEAST MODE
* Dynamic programming and recursion
** TODO Recursive String Permutations
** TODO Compute nth Fibonacci Number
** TODO Making Change
** TODO The Cake Thief
** TODO Balanced Binary Tree
** TODO Binary Search Tree Checker
** TODO 2nd Largest Item in a Binary Search Tree
* Queues and stacks
** TODO Largest Stack
** TODO Implement A Queue With Two Stacks
** TODO Parenthesis Matching
** TODO Bracket Validator
* Linked lists
** DONE Delete Node
** TODO Does This Linked List Have A Cycle?
** TODO Reverse A Linked List
** TODO Kth to Last Node in a Singly-Linked List
** TODO Find Repeat, Space Edition BEAST MODE
* System design
** TODO URL Shortener
** TODO MillionGazillion
** TODO Find Duplicate Files
* General programming
** TODO Rectangular Love
** TODO Temperature Tracker
* Bit manipulation
** TODO Binary Numbers
** TODO 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
* JavaScript
** TODO JavaScript Scope
** TODO What&#39;s Wrong with This JavaScript?
* Coding interview tips
** TODO How The Coding Interview Works
** TODO General Coding Interview Advice
** TODO Impostor Syndrome
** TODO Why You Hit Dead Ends
** TODO Tips for Getting Unstuck
** TODO The 24 Hours Before Your Interview
** TODO Beating Behavioral Questions
** TODO Managing Your Interview Timeline