diff --git a/dotfiles/lib/python/add_up_to.py b/dotfiles/lib/python/add_up_to.py new file mode 100644 index 00000000..27fb5077 --- /dev/null +++ b/dotfiles/lib/python/add_up_to.py @@ -0,0 +1,43 @@ +def count_unique_sums2(number, maximum_size): + maximum_to_try = min(number, maximum_size) + 1 + the_range = list(range(1, maximum_to_try)) + + all_sums = [] + for max_in_sum in the_range: + if max_in_sum == number: + all_sums.extend([[number]]) + continue + new_sums = count_unique_sums(number-max_in_sum, max_in_sum) + all_sums.extend( + [ + sum_so_far + [max_in_sum] + for sum_so_far in new_sums + ] + ) + + return all_sums + + +unique_sum_counts = {} + + +def count_unique_sums(number, maximum_size): + if (number, maximum_size) in unique_sum_counts: + return unique_sum_counts[(number, maximum_size)] + + maximum_to_try = min(number, maximum_size) + 1 + the_range = list(range(1, maximum_to_try)) + + sum_count = 0 + for max_in_sum in the_range: + if max_in_sum == number: + sum_count += 1 + continue + sum_count += count_unique_sums(number-max_in_sum, max_in_sum) + + unique_sum_counts[(number, maximum_size)] = sum_count + return sum_count + + +if __name__ == '__main__': + print(count_unique_sums(100, 100)) diff --git a/dotfiles/lib/python/lru_cache.py b/dotfiles/lib/python/lru_cache.py new file mode 100644 index 00000000..166e0b86 --- /dev/null +++ b/dotfiles/lib/python/lru_cache.py @@ -0,0 +1,84 @@ +class Node(object): + def __init__(self, key, value, next_node=None, prev_node=None): + self.key = key + self.value = value + self.next_node = next_node + self.prev_node = prev_node + + def print_list(self): + print("{0} - {1}".format(self.key, self.value)) + if self.next_node is not None: + assert self == self.next_node.prev_node + self.next_node.print_list() + else: + print("next node is None") + if self.prev_node is not None: + assert self.prev_node.next_node == self + + +class LRUCache(object): + def __init__(self, capacity): + self.capacity = capacity + self.cache = {} + self.head = None + self.tail = None + + def put(self, key, value): + """ + If key already exists, replace the current value with the new value. + If the key doesn't exist, add the new key/value entry to the cache. + If the addition of the new entry causes the number of entries to exceed + num_entries, remove the oldest entry based on the last time the entry is + accessed (either through put or get). + """ + if key in self.cache: + node = self.cache[key] + node.value = value + self.move_to_tail(node) + return + + if len(self.cache) >= self.capacity: + old_head = self.remove_from_head() + del self.cache[old_head.key] + + new_node = Node(key, value) + self.set_new_tail(new_node) + self.cache[key] = new_node + + def set_new_tail(self, node): + node.prev_node = self.tail + if self.tail is not None: + self.tail.next_node = node + self.tail = node + if self.head is None: + self.head = node + + def move_to_tail(self, node): + if node is self.tail: + return + if node.prev_node is None: # This is the head + if node.next_node is not None: + self.head = node.next_node + node.next_node.prev_node = None + else: + node.prev_node.next_node = node.next_node + node.next_node.prev_node = node.prev_node + + node.prev_node = self.tail + self.tail.next_node = node + self.tail = node + self.tail.next_node = None + + def remove_from_head(self): + previous_head = self.head + self.head = self.head.next_node + self.head.prev_node = None + return previous_head + + def get(self, key): + """Return the value associated with the key, or None if the key doesn't + exist.""" + node = self.cache.get(key) + if node is not None: + self.move_to_tail(node) + return node.value diff --git a/dotfiles/lib/python/powerset.py b/dotfiles/lib/python/powerset.py new file mode 100644 index 00000000..dc537ef8 --- /dev/null +++ b/dotfiles/lib/python/powerset.py @@ -0,0 +1,29 @@ +import collections +import copy + + +def powerset(elems): + counts = collections.defaultdict(int) + for elem in elems: + counts[elem] += 1 + return powerset_helper(counts.items()) + + +def powerset_helper(elems): + last_generation = [[]] + for (elem, count) in elems: + next_generation = last_generation + for _ in range(count): + new_generation = [] + for subset in last_generation: + new_subset = copy.copy(subset) + new_subset.append(elem) + new_generation.append(new_subset) + next_generation.extend(new_generation) + last_generation = new_generation + last_generation = next_generation + return last_generation + + +if __name__ == '__main__': + print(len(powerset(range(23)))) diff --git a/dotfiles/lib/python/score_parentheses.py b/dotfiles/lib/python/score_parentheses.py new file mode 100755 index 00000000..a3f2d923 --- /dev/null +++ b/dotfiles/lib/python/score_parentheses.py @@ -0,0 +1,31 @@ +#! /usr/bin/env python +import sys + +def score_parentheses(input_string, index=0): + if index >= len(input_string): + return (0, index) + if input_string[index] == '(': + index += 1 + else: + raise Exception("Invalid parentheses") + + children_score, index = score_children(input_string, index) + + if input_string[index] == ')': + index += 1 + else: + raise Exception("Invalid parentheses") + + return (children_score * 2 if children_score > 0 else 1, index) + +def score_children(input_string, index=0): + input_length = len(input_string) + children_score = 0 + while index < input_length and input_string[index] == '(': + child_score, index = score_parentheses(input_string, index) + children_score += child_score + return (children_score, index) + + +if __name__ == '__main__': + print (score_children(sys.argv[1])) diff --git a/dotfiles/lib/python/sliding_median.py b/dotfiles/lib/python/sliding_median.py new file mode 100644 index 00000000..e69de29b diff --git a/dotfiles/lib/python/sudoku.py b/dotfiles/lib/python/sudoku.py new file mode 100644 index 00000000..6bc4a592 --- /dev/null +++ b/dotfiles/lib/python/sudoku.py @@ -0,0 +1,86 @@ +goodpuzzle = [ + [1,2,3,4,5,6,7,8,9], + [4,5,6,7,8,9,1,2,3], + [7,8,9,1,2,3,4,5,6], + [2,3,4,5,6,7,8,9,1], + [5,6,7,8,9,1,2,3,4], + [8,9,1,2,3,4,5,6,7], + [3,4,5,6,7,8,9,1,2], + [6,7,8,9,1,2,3,4,5], + [9,1,2,3,4,5,6,7,8] +] + +badpuzzle1 = [ + [1,2,3,4,5,6,7,9,8], + [4,5,6,7,8,9,1,2,3], + [7,8,9,1,2,3,4,5,6], + [2,3,4,5,6,7,8,9,1], + [5,6,7,8,9,1,2,3,4], + [8,9,1,2,3,4,5,6,7], + [3,4,5,6,7,8,9,1,2], + [6,7,8,9,1,2,3,4,5], + [9,1,2,3,4,5,6,7,8] +] + +badpuzzle2 = [ + [1,2,3,4,5,6,7,2,9], + [4,5,6,7,8,9,1,8,3], + [7,8,9,1,2,3,4,5,6], + [2,3,4,5,6,7,8,9,1], + [5,6,7,8,9,1,2,3,4], + [8,9,1,2,3,4,5,6,7], + [3,4,5,6,7,8,9,1,2], + [6,7,8,9,1,2,3,4,5], + [9,1,2,3,4,5,6,7,8] +] + +badpuzzle3 = [ + [1,2,3,4,5,6,7,8,9], + [4,5,6,7,8,9,1,2,3], + [7,8,9,1,2,3,4,5,6], + [2,3,4,5,6,7,8,9,1], + [5,6,7,8,9,1,2,3,4], + [3,4,5,6,7,8,9,1,2], + [8,9,1,2,3,4,5,6,7], + [6,7,8,9,1,2,3,4,5], + [9,1,2,3,4,5,6,7,8] +] + + +one_to_nine = set(range(1, 10)) + + +def is_valid_sudoku_puzzle(sudoku_grid): + for row in sudoku_grid: + if set(row) != one_to_nine: + return False + + for i in range(9): + column = [sudoku_grid[j][i] for j in range(9)] + if set(column) != one_to_nine: + return False + + for i in range(3): + for j in range(3): + subgrid_elements = get_subgrid_elements(i, j, sudoku_grid) + if set(subgrid_elements) != one_to_nine: + return False + + return True + + +def get_subgrid_elements(subgrid_row, subgrid_column, sudoku_grid, subgrid_size=3): + subgrid_row_start = subgrid_row * subgrid_size + subgrid_column_start = subgrid_column * subgrid_size + + subgrid_elements = [] + for i in range(subgrid_row_start, subgrid_row_start + subgrid_size): + subgrid_elements += sudoku_grid[i][subgrid_column_start:subgrid_column_start+subgrid_size] + + return subgrid_elements + + +print(is_valid_sudoku_puzzle(goodpuzzle)) +print(is_valid_sudoku_puzzle(badpuzzle1)) +print(is_valid_sudoku_puzzle(badpuzzle2)) +print(is_valid_sudoku_puzzle(badpuzzle3))