├── .vscode ├── launch.json └── settings.json ├── README.md ├── abbreviation └── abbreviation.py ├── abs-sort └── abs-sort.py ├── accounts-transactions └── accounts-transactions.py ├── ancestors ├── ancestors.js ├── ancestors.py └── description.md ├── autocomplete ├── autocomplete.py └── description.md ├── company-org ├── company-org-alt.py ├── company-org.py └── description.md ├── debouncer └── debouncer.js ├── event-emitter ├── description.md ├── event-emitter.js └── event-emitter.py ├── fifo ├── description.md └── fifo.py ├── group-anagrams ├── description.md ├── group-anagrams.py ├── input.txt └── output.txt ├── hangman ├── description.md └── hangman.py ├── hungry-rabbit ├── description.md └── hungry-rabbit.py ├── increment └── increment.js ├── k-product └── k-product.py ├── largest-contiguous-block └── largest-contiguous-block.py ├── letter-combinations ├── description.md └── letter-combinations.py ├── lottery-ticket ├── description.md └── lottery-ticket.py ├── median-stream └── median-stream.py ├── min-num-boats └── min-num-boats.py ├── num-complements └── num-complements.py ├── num-islands ├── description.md └── num-islands.py ├── pattern-match ├── description.md ├── pattern-match.js └── pattern-match.py ├── pig-latin ├── description.md └── pig-latin.py ├── print-articles └── print-articles.py ├── print-columns └── print-columns.py ├── priority-expiry-cache └── priority-expiry-cache.py ├── rat-race └── rat-race.py ├── reverse-div-three.py └── reverse-div-three.py ├── reverse-string-brackets └── reverse-string-brackets.py ├── shortest-sublist-threshold └── shortest-sublist-threshold.py ├── smallest-common-num └── smallest-common-num.py ├── subarray-sum ├── description.md └── subarray-sum.py ├── task-scheduler └── task-scheduler.py ├── validate-number └── validate-number.py ├── validate-parenthesis ├── description.md └── validate-parenthesis.py ├── validate-xml └── validate-xml.py └── word-exists └── word-exists.py /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python: Current File", 9 | "type": "python", 10 | "request": "launch", 11 | "program": "${file}", 12 | "console": "integratedTerminal" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "/usr/local/bin/python3" 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Coding Challenges 2 | 3 | A variety of coding challenges in Python and JS, just for fun. 4 | 5 | ## Prerequisites 6 | 7 | 1. [Python](https://www.python.org/ "https://www.python.org/") 8 | 2. [Node](https://nodejs.org/en/ "https://nodejs.org/en/") 9 | -------------------------------------------------------------------------------- /abbreviation/abbreviation.py: -------------------------------------------------------------------------------- 1 | # internationalization - i18n 2 | # foobar - f4r 3 | # it - it 4 | 5 | 6 | def abbrevation(word): 7 | if not word or len(word) < 3: 8 | return word 9 | 10 | return word[0] + str(len(word) - 2) + word[-1] 11 | 12 | 13 | print(abbrevation('internationalization')) 14 | print(abbrevation('foobar')) 15 | print(abbrevation('it')) 16 | print(abbrevation('a')) 17 | -------------------------------------------------------------------------------- /abs-sort/abs-sort.py: -------------------------------------------------------------------------------- 1 | # A = [-3, -1, 3, 5, 7] 2 | # B = [1, 3, 3, 5, 7] 3 | 4 | # A = [-6, -4, -1, 3, 5, 7] 5 | # result = [1, 3, 4, 5, 6, 7] 6 | 7 | 8 | def abs_sort(array): 9 | if not array: 10 | return [] 11 | 12 | left_idx = 0 13 | right_idx = len(array) - 1 14 | 15 | result = [0] * len(array) 16 | resultIdx = len(result) - 1 17 | 18 | while left_idx <= right_idx: 19 | if abs(array[left_idx]) > abs(array[right_idx]): 20 | result[resultIdx] = abs(array[left_idx]) 21 | left_idx += 1 22 | else: 23 | result[resultIdx] = abs(array[right_idx]) 24 | right_idx -= 1 25 | 26 | resultIdx -= 1 27 | 28 | return result 29 | 30 | 31 | print(abs_sort([-3, -1, 3, 5, 7])) 32 | print(abs_sort([-6, -4, -1, 3, 5, 7])) 33 | print(abs_sort([-6, -4, -3, -1])) 34 | print(abs_sort([3, 4, 9, 10])) 35 | -------------------------------------------------------------------------------- /accounts-transactions/accounts-transactions.py: -------------------------------------------------------------------------------- 1 | from bisect import bisect_right 2 | 3 | 4 | class Account(): 5 | def __init__(self, account_id, ts, value): 6 | self.account_id = account_id 7 | self.timestamps = [ts] 8 | self.balances = [value] 9 | self.values = [value] 10 | 11 | 12 | class Accounts: 13 | def __init__(self): 14 | self.accounts = {} 15 | 16 | def credit(self, account_id, ts, value): 17 | if account_id not in self.accounts: 18 | self.accounts.setdefault( 19 | account_id, Account(account_id, ts, value)) 20 | else: 21 | account = self.accounts[account_id] 22 | account.timestamps.append(ts) 23 | account.balances.append(account.balances[-1] + value) 24 | account.values.append(value) 25 | 26 | def debit(self, account_id, ts, value): 27 | if account_id not in self.accounts: 28 | self.accounts.setdefault( 29 | account_id, Account(account_id, ts, -value)) 30 | else: 31 | account = self.accounts[account_id] 32 | account.timestamps.append(ts) 33 | account.balances.append(account.balances[-1] - value) 34 | account.values.append(-value) 35 | 36 | def current(self, account_id): 37 | if account_id not in self.accounts: 38 | return None 39 | account = self.accounts[account_id] 40 | return account.balances[-1] 41 | 42 | def balance_change(self, account_id, start_ts, end_ts): 43 | if account_id not in self.accounts: 44 | return None 45 | account = self.accounts[account_id] 46 | start_idx = bisect_right(account.timestamps, start_ts) 47 | end_idx = bisect_right(account.timestamps, end_ts) 48 | 49 | return account.balances[end_idx - 1] - account.balances[start_idx - 1] 50 | 51 | 52 | accounts = Accounts() 53 | accounts.credit(1, 1, 100) 54 | accounts.debit(1, 3, 50) 55 | accounts.credit(1, 5, 20) 56 | accounts.debit(1, 7, 10) 57 | print(accounts.current(1)) 58 | print(accounts.balance_change(1, 2, 6)) 59 | print(accounts.balance_change(1, 3, 5)) 60 | -------------------------------------------------------------------------------- /ancestors/ancestors.js: -------------------------------------------------------------------------------- 1 | function getAncestors(child, ancestors, personMap) { 2 | for (let parent of personMap.get(child)) { 3 | if (!ancestors.has(parent)) { 4 | ancestors.set( 5 | parent, 6 | ancestors.has(child) ? ancestors.get(child) + 1 : 0 7 | ); 8 | getAncestors(parent, ancestors, personMap); 9 | } 10 | } 11 | } 12 | 13 | function checkAncestors(child1, child2) { 14 | for (let [ancestor, val] of child1) { 15 | if (child2.has(ancestor)) { 16 | return true; 17 | } 18 | } 19 | return false; 20 | } 21 | 22 | function shareAncestor(pairs, child1, child2) { 23 | const personMap = parentChildRelationships(pairs); 24 | const child1Ancestors = new Map(); 25 | const child2Ancestors = new Map(); 26 | getAncestors(child1, child1Ancestors, personMap); 27 | getAncestors(child2, child2Ancestors, personMap); 28 | 29 | return checkAncestors(child1Ancestors, child2Ancestors); 30 | } 31 | 32 | function parentChildRelationships(pairs) { 33 | const personMap = new Map(); 34 | pairs.forEach(([parent, child]) => { 35 | if (!personMap.has(parent)) { 36 | personMap.set(parent, []); 37 | } 38 | 39 | if (!personMap.has(child)) { 40 | personMap.set(child, [parent]); 41 | } else { 42 | personMap.get(child).push(parent); 43 | } 44 | }); 45 | 46 | return personMap; 47 | } 48 | 49 | const parentChildPairs = [ 50 | [1, 3], 51 | [2, 3], 52 | [3, 6], 53 | [5, 6], 54 | [5, 7], 55 | [4, 5], 56 | [4, 8], 57 | [8, 9], 58 | [6, 10] 59 | ]; 60 | 61 | console.log(shareAncestor(parentChildPairs, 8, 9)); 62 | -------------------------------------------------------------------------------- /ancestors/ancestors.py: -------------------------------------------------------------------------------- 1 | def create_ancestor_graph(relationships): 2 | ancestor_graph = {} 3 | for parent, child in relationships: 4 | if parent not in ancestor_graph: 5 | ancestor_graph[parent] = [] 6 | 7 | if child not in ancestor_graph: 8 | ancestor_graph[child] = [] 9 | 10 | ancestor_graph[child].append(parent) 11 | 12 | return ancestor_graph 13 | 14 | 15 | def earliest_ancestor(child, ancestor_graph): 16 | if child not in ancestor_graph or not ancestor_graph[child]: 17 | return -1 18 | 19 | queue = [child] 20 | visited = set() 21 | 22 | while queue: 23 | tempq = [] 24 | for person in queue: 25 | for ancestor in ancestor_graph[person]: 26 | if ancestor not in visited: 27 | visited.add(ancestor) 28 | tempq.append(ancestor) 29 | 30 | if not tempq: 31 | return queue[0] 32 | 33 | queue = tempq 34 | 35 | return -1 36 | 37 | 38 | def get_all_ancestors(child, ancestor_graph): 39 | if child not in ancestor_graph or not ancestor_graph[child]: 40 | return set() 41 | 42 | queue = [child] 43 | visited = set() 44 | 45 | while queue: 46 | tempq = [] 47 | for person in queue: 48 | for ancestor in ancestor_graph[person]: 49 | if ancestor not in visited: 50 | visited.add(ancestor) 51 | tempq.append(ancestor) 52 | 53 | queue = tempq 54 | 55 | return visited 56 | 57 | 58 | def has_common_ancestor(child1, child2, ancestor_graph): 59 | child1_ancestors = get_all_ancestors(child1, ancestor_graph) 60 | child2_ancestors = get_all_ancestors(child2, ancestor_graph) 61 | 62 | return len(child1_ancestors & child2_ancestors) > 0 63 | 64 | 65 | def one_or_zero_parents(ancestor_graph): 66 | children = [] 67 | for child in ancestor_graph.keys(): 68 | if len(ancestor_graph[child]) <= 1: 69 | children.append(child) 70 | return children 71 | 72 | 73 | parent_child_pairs1 = [ 74 | (2, 3), (3, 15), (3, 6), (5, 6), (5, 7), 75 | (4, 5), (4, 8), (4, 9), (9, 11), (14, 4), 76 | ] 77 | ancestor_graph1 = create_ancestor_graph(parent_child_pairs1) 78 | print(earliest_ancestor(8, ancestor_graph1)) # 14 79 | print(earliest_ancestor(7, ancestor_graph1)) # 14 80 | print(earliest_ancestor(6, ancestor_graph1)) # 14 81 | print(earliest_ancestor(15, ancestor_graph1)) # 2 82 | print(earliest_ancestor(14, ancestor_graph1)) # -1 83 | print() 84 | print(has_common_ancestor(3, 8, ancestor_graph1)) # false 85 | print(has_common_ancestor(5, 8, ancestor_graph1)) # true 86 | print(has_common_ancestor(6, 8, ancestor_graph1)) # true 87 | print(has_common_ancestor(6, 9, ancestor_graph1)) # true 88 | print(has_common_ancestor(1, 3, ancestor_graph1)) # false 89 | print(has_common_ancestor(7, 11, ancestor_graph1)) # true 90 | print(has_common_ancestor(6, 5, ancestor_graph1)) # true 91 | print(has_common_ancestor(5, 6, ancestor_graph1)) # true 92 | print() 93 | print(one_or_zero_parents(ancestor_graph1)) 94 | print() 95 | 96 | parent_child_pairs2 = [ 97 | (2, 3), (3, 15), (3, 6), (5, 6), (5, 7), 98 | (4, 5), (4, 8), (4, 9), (9, 11), (14, 2), 99 | ] 100 | ancestor_graph2 = create_ancestor_graph(parent_child_pairs2) 101 | print(earliest_ancestor(8, ancestor_graph2)) # 4 102 | print(earliest_ancestor(7, ancestor_graph2)) # 4 103 | print(earliest_ancestor(6, ancestor_graph2)) # 14 104 | print(earliest_ancestor(15, ancestor_graph2)) # 14 105 | print(earliest_ancestor(14, ancestor_graph2)) # -1 106 | print() 107 | print(has_common_ancestor(4, 12, ancestor_graph2)) # false 108 | print(has_common_ancestor(11, 6, ancestor_graph2)) # true 109 | print(has_common_ancestor(11, 3, ancestor_graph2)) # false 110 | print() 111 | print(one_or_zero_parents(ancestor_graph2)) 112 | -------------------------------------------------------------------------------- /ancestors/description.md: -------------------------------------------------------------------------------- 1 | # Ancestors 2 | 3 | Suppose we have some input data describing a graph of relationships between parents and children over multiple generations. The data is formatted as a list of (parent, child) pairs, where each individual is assigned a unique integer identifier. 4 | 5 | Write a function that, for a given individual in our dataset, returns their earliest known ancestor -- the one at the farthest distance from the input individual. If there is more than one ancestor tied for “earliest”, return any one of them. If the input individual has no parents, the function should return null (or -1). 6 | 7 | ## Example 8 | 9 | 1 2 4 10 | \ / / \ 11 | 3 5 8 12 | \ / \ \ 13 | 6 7 9 14 | 15 | ### Input: 16 | 17 | [ 18 | [1, 3], 19 | [2, 3], 20 | [3, 6], 21 | [5, 6], 22 | [5, 7], 23 | [4, 5], 24 | [4, 8], 25 | [8, 9] 26 | ]; 27 | 28 | ### Output: 29 | 30 | 8 => 4 31 | 7 => 4 32 | 6 => 1, 2, or 4 33 | 34 | ## Run the program 35 | 36 | In the folder run the command: 37 | 38 | ``` 39 | node ancestors.js 40 | ``` 41 | -------------------------------------------------------------------------------- /autocomplete/autocomplete.py: -------------------------------------------------------------------------------- 1 | class Autocomplete: 2 | def __init__(self): 3 | self.trie = {} 4 | 5 | def get_words(self, start, temp, words): 6 | if start['isWord']: 7 | words.append((temp, start['isWord'])) 8 | 9 | for key, val in start.items(): 10 | if key != 'isWord': 11 | self.get_words(val, temp + key, words) 12 | 13 | def get(self, prefix): 14 | current = self.trie 15 | for char in prefix: 16 | if char not in current: 17 | return [] 18 | current = current[char] 19 | 20 | words = [] 21 | self.get_words(current, prefix, words) 22 | sorted_words = sorted(words, key=lambda x: x[1], reverse=True) 23 | return sorted_words 24 | 25 | def put(self, word): 26 | current = self.trie 27 | for char in word: 28 | if char not in current: 29 | current[char] = {'isWord': 0} 30 | current = current[char] 31 | current['isWord'] += 1 32 | 33 | 34 | autocomplete = Autocomplete() 35 | autocomplete.put('boat') 36 | autocomplete.put('boat') 37 | autocomplete.put('boat') 38 | 39 | autocomplete.put('goat') 40 | autocomplete.put('book') 41 | autocomplete.put('booking') 42 | print(autocomplete.get('bo')) 43 | -------------------------------------------------------------------------------- /autocomplete/description.md: -------------------------------------------------------------------------------- 1 | # Autocomplete 2 | 3 | We're going to make our own autocomplete application! The application must perform two types of operations: 4 | 5 | 1. Add word. This must store the word as a new entry in the application. 6 | 2. Get words. A string denoting a partial word to search the application for. It must find all of the words it is a prefix for and return them in a list. 7 | 8 | Given n sequential add and get operations, perform each operation in order. 9 | 10 | ## Example 11 | 12 | ### Input: 13 | 14 | add boat 15 | add goat 16 | add booking 17 | get bo 18 | get goat 19 | 20 | ### Output: 21 | 22 | boat, booking 23 | goat 24 | 25 | ## Run the program 26 | 27 | In the folder run the command: 28 | 29 | ``` 30 | python autocomplete.py 31 | ``` 32 | -------------------------------------------------------------------------------- /company-org/company-org-alt.py: -------------------------------------------------------------------------------- 1 | def company_org(employees): 2 | managers_map = {} 3 | for employee in employees: 4 | if employee[1] not in managers_map: 5 | managers_map[employee[1]] = [] 6 | 7 | if employee[0] not in managers_map: 8 | managers_map[employee[0]] = [] 9 | 10 | managers_map[employee[1]].append(employee) 11 | 12 | if not managers_map[None]: 13 | print('No CEO') 14 | return None 15 | 16 | dash_set = {managers_map[None][0][0]: ''} 17 | stack = [managers_map[None][0]] 18 | 19 | while stack: 20 | current = stack.pop() 21 | print('{}{} ({}) {}'.format( 22 | dash_set[current[0]], current[0], current[2], current[3])) 23 | 24 | for reportee in managers_map[current[0]]: 25 | dash_set[reportee[0]] = dash_set[reportee[1]] + '-' 26 | stack.append(reportee) 27 | 28 | 29 | employees = [ 30 | ['Karl', 'Nancy', 'Manager', 2009], 31 | ['Adam', 'Karl', 'Technician', 2010], 32 | ['Bob', 'Karl', 'Technician', 2012], 33 | ['Cathy', 'Wendy', 'Manager', 2013], 34 | ['Nancy', None, 'CEO', 2007], 35 | ['Wendy', 'Nancy', 'Technician', 2012], 36 | ['John', 'Adam', 'Woker', 2014] 37 | ] 38 | 39 | company_org(employees) 40 | -------------------------------------------------------------------------------- /company-org/company-org.py: -------------------------------------------------------------------------------- 1 | def company_org(employees): 2 | managers_map = {} 3 | for employee in employees: 4 | if employee[1] not in managers_map: 5 | managers_map[employee[1]] = [] 6 | 7 | if employee[0] not in managers_map: 8 | managers_map[employee[0]] = [] 9 | 10 | managers_map[employee[1]].append(employee) 11 | 12 | if not managers_map[None]: 13 | print('No CEO') 14 | return None 15 | 16 | dash_set = {managers_map[None][0][0]: ''} 17 | stack = [managers_map[None][0]] 18 | 19 | while stack: 20 | current = stack.pop() 21 | print('{}{} ({}) {}'.format( 22 | dash_set[current[0]], current[0], current[2], current[3])) 23 | 24 | for reportee in managers_map[current[0]]: 25 | dash_set[reportee[0]] = dash_set[reportee[1]] + '-' 26 | stack.append(reportee) 27 | 28 | 29 | employees = [ 30 | ['Karl', 'Nancy', 'Manager', 2009], 31 | ['Adam', 'Karl', 'Technician', 2010], 32 | ['Bob', 'Karl', 'Technician', 2012], 33 | ['Cathy', 'Wendy', 'Manager', 2013], 34 | ['Nancy', None, 'CEO', 2007], 35 | ['Wendy', 'Nancy', 'Technician', 2012], 36 | ['John', 'Adam', 'Woker', 2014] 37 | ] 38 | 39 | company_org(employees) 40 | -------------------------------------------------------------------------------- /company-org/description.md: -------------------------------------------------------------------------------- 1 | # Company org 2 | 3 | Given a list of employees and their direct manager, print out the company org chart. 4 | 5 | ## Example 6 | 7 | ### Input: 8 | 9 | **Employee Name, Manager Name, Position, Year Hired** 10 | 11 | Karl,Nancy,Manager,2009 12 | Adam,Karl,Technician,2010 13 | Bob,Karl,Technician,2012 14 | John, Adam, Apprentice,2012 15 | Cathy,Wendy,Manager,2013 16 | Nancy,NULL,CEO,2007 17 | Wendy,Nancy,Technician,2012 18 | 19 | ### Output: 20 | 21 | Nancy (CEO) 2007 22 | -Karl (Manager) 2009 23 | --Adam (Technician) 2010 24 | ---John (Apprentice) 2012 25 | --Bob (Technician) 2012 26 | -Wendy (Manager) 2012 27 | —-Cathy (Technician) 2013 28 | 29 | ## Run the program 30 | 31 | In the folder run the command: 32 | 33 | ``` 34 | python company-org.py 35 | ``` 36 | -------------------------------------------------------------------------------- /debouncer/debouncer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Implement a debounce function in javascript 3 | When a user types into an input field, trigger a function to an api endpoint after 500ms 4 | Timer resets on each key press within 500ms window 5 | */ 6 | 7 | function debouncer() { 8 | let timer = null; 9 | 10 | return (callback, immediately, ...payload) => { 11 | clearTimeout(timer); 12 | 13 | if (immediately) { 14 | callback(...payload); 15 | } else { 16 | timer = setTimeout(() => { 17 | callback(...payload); 18 | }, 500); 19 | } 20 | }; 21 | } 22 | 23 | function print(string1, string2) { 24 | console.log(string1 + string2); 25 | } 26 | 27 | const debounce = debouncer(); 28 | debounce(console.log, false, "Hello World"); 29 | setTimeout(() => { 30 | debounce(print, false, "Hello World log 1", " additional string"); 31 | }, 300); 32 | setTimeout(() => { 33 | debounce(console.log, false, "Hello World do not log"); 34 | }, 900); 35 | setTimeout(() => { 36 | debounce(console.log, true, "Hello World log still log this"); 37 | }, 1000); 38 | setTimeout(() => { 39 | debounce(console.log, false, "Hello World log will be logged"); 40 | }, 1000); 41 | -------------------------------------------------------------------------------- /event-emitter/description.md: -------------------------------------------------------------------------------- 1 | # Event emitter 2 | 3 | We're going to make our own event emitter application! The application must perform three types of operations: 4 | 5 | 1. Subscribe. Store the callback to be invoked when the event is triggered. This must store the callback as a new entry for the event. 6 | 2. Unsubscribe. Removes the callback specified or all of the callbacks stored for a given event. 7 | 3. Emit. Invoke all callbacks subscribed to the event emitted with the aruments provided. 8 | 9 | Given n sequential add and get operations, perform each operation in order. 10 | 11 | ## Example 12 | 13 | **Operation, Action, Callback** 14 | subscribe, print, console.log 15 | 16 | **Operation, Action, Arguments** 17 | emit print "Test" 18 | 19 | **Operation, Action, Callback** 20 | unsubscribe, print, console.log 21 | 22 | **Operation, Action, Arguments** 23 | emit print "Test" 24 | 25 | ### Output: 26 | 27 | Test 28 | 29 | ## Run the program 30 | 31 | In the folder run the command: 32 | 33 | ``` 34 | node event-emitter.js 35 | ``` 36 | -------------------------------------------------------------------------------- /event-emitter/event-emitter.js: -------------------------------------------------------------------------------- 1 | class EventEmitter { 2 | constructor() { 3 | this.map = new Map(); 4 | } 5 | 6 | subscribe(eventName, callback, options) { 7 | if (this.map.has(eventName)) { 8 | this.map.get(eventName).push(callback); 9 | } else { 10 | this.map.set(eventName, [callback]); 11 | } 12 | } 13 | 14 | emit(eventName, ...args) { 15 | if (this.map.has(eventName)) { 16 | for (let callback of this.map.get(eventName)) { 17 | callback(...args); 18 | } 19 | } 20 | } 21 | 22 | unsubscribe(eventName, callback = null) { 23 | if (this.map.has(eventName)) { 24 | if (callback) { 25 | this.map.set( 26 | eventName, 27 | this.map.get(eventName).filter(callback => callback !== callback) 28 | ); 29 | } else { 30 | this.map.delete(eventName); 31 | } 32 | } 33 | } 34 | } 35 | 36 | const eventEmitter = new EventEmitter(); 37 | const callback = console.log; 38 | eventEmitter.subscribe("print", callback); 39 | eventEmitter.emit("print", "Hello World"); 40 | eventEmitter.subscribe("print", callback); 41 | eventEmitter.emit("print", "Test"); 42 | eventEmitter.unsubscribe("print"); 43 | eventEmitter.emit("print", "Don't print"); 44 | eventEmitter.subscribe("print", callback); 45 | eventEmitter.emit("print", "Print"); 46 | eventEmitter.unsubscribe("print", callback); 47 | eventEmitter.emit("print", "Don't print"); 48 | -------------------------------------------------------------------------------- /event-emitter/event-emitter.py: -------------------------------------------------------------------------------- 1 | class EventEmitter: 2 | def __init__(self): 3 | self.events = {} 4 | 5 | def subscribe(self, event, callback): 6 | if event in self.events: 7 | self.events[event].append(callback) 8 | else: 9 | self.events[event] = [callback] 10 | 11 | def unsubscribe(self, event, callback=None): 12 | if event not in self.events: 13 | return 14 | 15 | if not callback: 16 | self.events.pop(event, None) 17 | else: 18 | self.events[event] = list( 19 | filter(lambda c: c != callback, self.events[event])) 20 | 21 | def emit(self, event, *args): 22 | if event not in self.events: 23 | return 24 | 25 | for callback in self.events[event]: 26 | callback(*args) 27 | 28 | 29 | def print_callback(*args): 30 | for arg in args: 31 | print(arg) 32 | 33 | 34 | eventEmitter = EventEmitter() 35 | eventEmitter.subscribe("print", print_callback) 36 | eventEmitter.emit("print", "Hello World") 37 | eventEmitter.subscribe("print", print_callback) 38 | eventEmitter.emit("print", "Test") 39 | eventEmitter.unsubscribe("print") 40 | eventEmitter.emit("print", "Don't print") 41 | eventEmitter.subscribe("print", print_callback) 42 | eventEmitter.emit("print", "Print") 43 | eventEmitter.unsubscribe("print", print_callback) 44 | eventEmitter.emit("print", "Don't print") 45 | -------------------------------------------------------------------------------- /fifo/description.md: -------------------------------------------------------------------------------- 1 | # FIFO data structure 2 | 3 | Implement a FIFO (first in, first out) data struture with O(1) push and O(1) pop operations, without using a libary or native implementation. 4 | 5 | Given n sequential add and get operations, perform each operation in order. 6 | 7 | ## Example 8 | 9 | ### Input: 10 | 11 | put 1 12 | put 2 13 | put 3 14 | pop 15 | pop 16 | pop 17 | 18 | ### Output: 19 | 20 | 1 21 | 2 22 | 3 23 | 24 | ## Run the program 25 | 26 | In the folder run the command: 27 | 28 | ``` 29 | python fifo.py 30 | ``` 31 | -------------------------------------------------------------------------------- /fifo/fifo.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | class FIFO: 5 | def __init__(self, size=5): 6 | self.list = [0] * size 7 | self.push_idx = 0 8 | self.pop_idx = 0 9 | 10 | def push(self, val): 11 | self.list[self.push_idx] = val 12 | self.push_idx = (self.push_idx + 1) % len(self.list) 13 | 14 | if self.push_idx == self.pop_idx: 15 | self.increase_lst_size() 16 | 17 | def pop(self): 18 | if self.pop_idx == self.push_idx: 19 | return None 20 | 21 | val = self.list[self.pop_idx] 22 | self.pop_idx = (self.pop_idx + 1) % len(self.list) 23 | 24 | return val 25 | 26 | def increase_lst_size(self): 27 | new_list = [0] * (len(self.list) * 2) 28 | new_list_idx = 0 29 | 30 | for i in xrange(0, len(self.list)): 31 | idx = (self.push_idx + i) % len(self.list) 32 | new_list[new_list_idx] = self.list[idx] 33 | new_list_idx += 1 34 | 35 | self.list = new_list 36 | self.push_idx = new_list_idx 37 | self.pop_idx = 0 38 | 39 | 40 | class FIFOTests(unittest.TestCase): 41 | def test_push_pop(self): 42 | fifo = FIFO() 43 | fifo.push(1) 44 | self.assertEqual(fifo.pop(), 1) 45 | 46 | def test_increase_size(self): 47 | fifo = FIFO(2) 48 | fifo.push(1) 49 | fifo.push(2) 50 | self.assertEqual(len(fifo.list), 4) 51 | 52 | def test_wrap(self): 53 | fifo = FIFO(3) 54 | fifo.push(1) 55 | fifo.push(2) 56 | fifo.pop() 57 | fifo.pop() 58 | fifo.push(3) 59 | fifo.push(4) 60 | self.assertEqual(len(fifo.list), 3) 61 | self.assertEqual(fifo.pop(), 3) 62 | self.assertEqual(fifo.pop(), 4) 63 | 64 | 65 | if __name__ == '__main__': 66 | unittest.main() 67 | -------------------------------------------------------------------------------- /group-anagrams/description.md: -------------------------------------------------------------------------------- 1 | # Group Anagrams 2 | 3 | Given a list of words, group the anagrams together. 4 | 5 | _Anagram: A word or phrase formed by rearranging the letters of a different word or phrase, using all the original letters exactly once._ 6 | 7 | ## Example 8 | 9 | **Input:** 10 | 11 | ``` 12 | eat 13 | tea 14 | tan 15 | ate 16 | nat 17 | bat 18 | ``` 19 | 20 | **Output:** 21 | 22 | ``` 23 | "ate","eat","tea" 24 | "nat","tan" 25 | "bat" 26 | ``` 27 | 28 | ## Input 29 | 30 | Read the words from _input.txt_. 31 | 32 | ## Output 33 | 34 | Write the groups of anagrams to _output.txt_. 35 | 36 | ## Run the program 37 | 38 | In the folder run the command: 39 | 40 | ``` 41 | python group-anagrams.py 42 | ``` 43 | -------------------------------------------------------------------------------- /group-anagrams/group-anagrams.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | 3 | 4 | def toKeyString(word): 5 | return ''.join(sorted(word.lower())) 6 | 7 | 8 | def findAnagrams(arr): 9 | anagrams = OrderedDict() 10 | for word in arr: 11 | key = toKeyString(word) 12 | 13 | if key in anagrams: 14 | anagrams[key].append(word) 15 | else: 16 | anagrams[key] = [word] 17 | 18 | return anagrams 19 | 20 | 21 | def writeToFile(anagrams, file): 22 | file = open(file, 'w') 23 | for key, value in anagrams.iteritems(): 24 | file.write(', '.join(value)) 25 | file.write('\n') 26 | 27 | file.close() 28 | 29 | 30 | def getInputFromFile(file): 31 | with open(file) as f: 32 | content = f.readlines() 33 | return [x.strip() for x in content] 34 | 35 | 36 | input = getInputFromFile('input.txt') 37 | writeToFile(findAnagrams(input), 'output.txt') 38 | -------------------------------------------------------------------------------- /group-anagrams/input.txt: -------------------------------------------------------------------------------- 1 | Boat4 2 | Road 3 | doar 4 | abote 5 | abt 6 | bat 7 | abota 8 | 4Boat 9 | Bo at4 10 | obat 4 11 | -------------------------------------------------------------------------------- /group-anagrams/output.txt: -------------------------------------------------------------------------------- 1 | Boat4, 4Boat 2 | Road, doar 3 | abote 4 | abt, bat 5 | abota 6 | Bo at4, obat 4 7 | -------------------------------------------------------------------------------- /hangman/description.md: -------------------------------------------------------------------------------- 1 | # Hangman 2 | 3 | Simple game of hangman. 4 | 5 | ## Run the program 6 | 7 | In the folder run the command: 8 | 9 | ``` 10 | python hangman.py 11 | ``` 12 | -------------------------------------------------------------------------------- /hangman/hangman.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | def greeting(): 5 | print "***** Hangman ****\n" 6 | 7 | 8 | def get_word(): 9 | return 'hangman' 10 | 11 | 12 | def generate_string(word, letters): 13 | string = [] 14 | for l in word: 15 | if l in letters: 16 | string.append(l) 17 | else: 18 | string.append('_') 19 | return ''.join(string) 20 | 21 | 22 | def has_won(word, letters): 23 | for l in word: 24 | if l not in letters: 25 | return False 26 | 27 | return True 28 | 29 | 30 | def is_valid(letter, letters): 31 | regex = r"[a-zA-Z]" 32 | if not re.search(regex, letter): 33 | return False 34 | 35 | if letter in letters: 36 | return False 37 | return True 38 | 39 | 40 | def main(): 41 | greeting() 42 | 43 | word = get_word() 44 | 45 | letters = set() 46 | 47 | while True: 48 | print generate_string(word, letters) 49 | 50 | if has_won(word, letters): 51 | print "Congrats, you've won!" 52 | return 53 | 54 | letter = raw_input("Enter a letter: ") 55 | 56 | if not is_valid(letter, letters): 57 | print "You've already selected that letter" 58 | 59 | letters.add(letter) 60 | 61 | 62 | main() 63 | -------------------------------------------------------------------------------- /hungry-rabbit/description.md: -------------------------------------------------------------------------------- 1 | # Hungry rabbit 2 | 3 | There is a rabbit that starts in the middle of an n x m matrix, n > 0, m > 0. 4 | Each element of a matrix is an integer representing points gained for being on the spot. 5 | If there are multiple possible "middles" then choose the one which has the highest point value to start on. 6 | On each iteration, the rabbit can move up, left, right, or down. 7 | The rabbit will always move to the next spot with the highest point value and will "consume" those points (set the point value in that position to 0). 8 | The rabbit spots when all positions around it are 0s. Calculate how many points the rabbit will score for a given m x n matrix. 9 | 10 | ## Example 11 | 12 | ### Input 13 | 14 | 5, 7, 8, 6, 3 15 | 0, 0, 7, 0, 4 16 | 4, 6, 3, 4, 9 17 | 3, 1, 0, 5, 8 18 | 19 | ### Output 20 | 21 | 27 22 | 23 | ## Run the program 24 | 25 | In the folder run the command: 26 | 27 | ``` 28 | python hungry-rabbit.py 29 | ``` 30 | -------------------------------------------------------------------------------- /hungry-rabbit/hungry-rabbit.py: -------------------------------------------------------------------------------- 1 | def hungry_rabbit_util(garden, row, col): 2 | max = 0 3 | next_row = None 4 | next_col = None 5 | 6 | for r, c in [[-1, 0], [1, 0], [0, -1], [0, 1]]: 7 | if row + r >= 0 and row + r < len(garden) and \ 8 | col + c >= 0 and col + c < len(garden[row]): 9 | if garden[row + r][col + c] > max: 10 | max = garden[row + r][col + c] 11 | next_row = row + r 12 | next_col = col + c 13 | 14 | carrots = garden[row][col] 15 | garden[row][col] = 0 16 | 17 | if max > 0 and next_row is not None and next_col is not None: 18 | carrots += hungry_rabbit_util(garden, next_row, next_col) 19 | 20 | return carrots 21 | 22 | 23 | def find_center(garden): 24 | row_options = [len(garden) // 2, len(garden) // 2] 25 | col_options = [len(garden[0]) // 2, len(garden[0]) // 2] 26 | 27 | # If even, 1st option is one less than half the length 28 | if len(garden) % 2 == 0: 29 | row_options[0] -= 1 30 | 31 | if len(garden[0]) % 2 == 0: 32 | col_options[0] -= 1 33 | 34 | max = 0 35 | row = None 36 | col = None 37 | 38 | for r_option in row_options: 39 | for c_option in col_options: 40 | if garden[r_option][c_option] > max: 41 | max = garden[r_option][c_option] 42 | row = r_option 43 | col = c_option 44 | 45 | return row, col 46 | 47 | 48 | def hungry_rabbit(garden): 49 | if len(garden) == 0 or len(garden[0]) == 0: 50 | return 0 51 | 52 | # create a copy of the garden so we can mutate it 53 | copy = [g_row[:] for g_row in garden] 54 | row, col = find_center(copy) 55 | 56 | if row is None or col is None: 57 | return 0 58 | 59 | return hungry_rabbit_util(copy, row, col) 60 | 61 | 62 | if __name__ == "__main__": 63 | garden = [ 64 | [5, 7, 8, 6, 3], 65 | [0, 0, 7, 0, 4], 66 | [4, 6, 3, 4, 9], 67 | [3, 1, 0, 5, 8] 68 | ] 69 | 70 | print hungry_rabbit(garden) 71 | -------------------------------------------------------------------------------- /increment/increment.js: -------------------------------------------------------------------------------- 1 | /* 2 | Topics: fundamentals, closures 3 | Create a function called incrementCounter 4 | incrementCount leverages a closure to keep track a variable that gets incremented 5 | 6 | Ex: 7 | incrementCounter() // returns 1 8 | incrementCounter() // returns 2 9 | incrementCounter() // returns 3 10 | 11 | Solution must leverage closures, should not use global variables or object instance properties 12 | */ 13 | 14 | function incrementCounter() { 15 | let counter = 0; 16 | return () => { 17 | counter++; 18 | return counter; 19 | }; 20 | } 21 | 22 | let counter = incrementCounter(); 23 | console.log(counter()); // return 1 24 | console.log(counter()); // return 2 25 | console.log(counter()); // return 3 26 | -------------------------------------------------------------------------------- /k-product/k-product.py: -------------------------------------------------------------------------------- 1 | """ 2 | Design/implement a class that supports inserting integers and getting the 3 | product of K most recently inserted numbers (K is provided at the time of 4 | construction). 5 | 6 | K = 3 7 | [1, 3] => 3 8 | [1, 3, 4] => 12 9 | [1, 3, 4, 0] => 0 10 | [1, 3, 4, 0, 6] => 0 11 | [1, 3, 4, 0, 6, 1] => 0 12 | [1, 3, 4, 0, 6, 1, 5] => 30 13 | """ 14 | 15 | from collections import deque 16 | 17 | 18 | class KProduct: 19 | def __init__(self, k): 20 | self.k = k 21 | self.numZeros = 0 22 | self.product = 1 23 | self.queue = deque() 24 | 25 | def insert(self, num): 26 | self.queue.append(num) 27 | if num == 0: 28 | self.numZeros += 1 29 | else: 30 | self.product *= num 31 | 32 | if len(self.queue) > self.k: 33 | poppedNum = self.queue.popleft() 34 | if poppedNum == 0: 35 | self.numZeros -= 1 36 | else: 37 | self.product /= poppedNum 38 | 39 | def getProduct(self): 40 | if self.numZeros > 0: 41 | return 0 42 | return self.product 43 | 44 | 45 | kProduct = KProduct(3) 46 | kProduct.insert(1) 47 | print(kProduct.getProduct()) 48 | kProduct.insert(3) 49 | print(kProduct.getProduct()) 50 | kProduct.insert(4) 51 | print(kProduct.getProduct()) 52 | kProduct.insert(0) 53 | print(kProduct.getProduct()) 54 | kProduct.insert(6) 55 | print(kProduct.getProduct()) 56 | kProduct.insert(1) 57 | print(kProduct.getProduct()) 58 | kProduct.insert(5) 59 | print(kProduct.getProduct()) 60 | -------------------------------------------------------------------------------- /largest-contiguous-block/largest-contiguous-block.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an 2-dimensional array of integers, find the size of the largest contiguous block (horizontally/vertically connected only) of numbers with the same value. 3 | 4 | 1 2 3 5 | 1 4 5 6 | 1 1 7 7 | 8 | 4 (of 1s) 9 | 10 | 11 | 1 2 5 1 7 12 | 1 9 9 7 4 13 | 1 1 9 9 0 14 | 15 | 4 16 | 17 | """ 18 | 19 | directions = [[1, 0], [-1, 0], [0, 1], [0, -1], 20 | [1, 1], [1, -1], [-1, -1], [-1, 1]] 21 | 22 | 23 | def dfs(matrix, row, col, visited): 24 | visited[row][col] = 1 25 | 26 | contiguousBlock = 1 27 | for r, c in directions: 28 | nextRow = row + r 29 | nextCol = col + c 30 | if (nextRow < 0 or nextRow >= len(matrix) or nextCol < 0 or nextCol >= len(matrix[row])): 31 | continue 32 | 33 | if (matrix[row][col] == matrix[nextRow][nextCol] and visited[nextRow][nextCol] == 0): 34 | num, count = dfs(matrix, nextRow, nextCol, visited) 35 | contiguousBlock += count 36 | 37 | return matrix[row][col], contiguousBlock 38 | 39 | 40 | def largestContiguousBlock(matrix): 41 | if not matrix or not matrix[0]: 42 | return None, 0 43 | 44 | visited = [[0] * len(matrix[0]) for _ in range(len(matrix))] 45 | largestBlock = 0 46 | largestNum = None 47 | 48 | for row in range(len(matrix)): 49 | for col in range(len(matrix[row])): 50 | if visited[row][col] == 0: 51 | num, block = dfs(matrix, row, col, visited) 52 | if block > largestBlock: 53 | largestBlock = block 54 | largestNum = num 55 | 56 | return largestNum, largestBlock 57 | 58 | 59 | matrix = [ 60 | [1, 2, 3], 61 | [1, 4, 5], 62 | [0, 1, 7] 63 | ] 64 | 65 | matrix2 = [ 66 | [1, 2, 5, 1, 7], 67 | [1, 7, 5, 7, 8], 68 | [1, 7, 7, 8, 5] 69 | ] 70 | 71 | largestMatrix = largestContiguousBlock(matrix) 72 | print('Number: {} Count: {}'.format(largestContiguousBlock( 73 | matrix2)[0], largestContiguousBlock(matrix2)[1])) 74 | -------------------------------------------------------------------------------- /letter-combinations/description.md: -------------------------------------------------------------------------------- 1 | # Letter Combinations 2 | 3 | Given a string containing digits and dictionary mapping digits to letters, return all possible letter combinations that the number could represent. 4 | 5 | ## Example 6 | 7 | **DICT** 8 | 9 | ``` 10 | { 11 | '1': 'ab', 12 | '2': 'de', 13 | '12': 'gh' 14 | } 15 | ``` 16 | 17 | **Input:** "12" 18 | **Output:** ['ad', 'ae', 'bd', 'be', 'g', 'h'] 19 | 20 | **Input:** "221" 21 | **Output:** ['dda', 'ddb', 'dea', 'deb', 'eda', 'edb', 'eea', 'eeb'] 22 | 23 | ## Run the program 24 | 25 | In the folder run the command: 26 | 27 | ``` 28 | python letter-combinations.py 29 | ``` 30 | -------------------------------------------------------------------------------- /letter-combinations/letter-combinations.py: -------------------------------------------------------------------------------- 1 | DICT = { 2 | '1': 'ab', 3 | '2': 'de', 4 | '12': 'gh' 5 | } 6 | 7 | 8 | def get_words(nums): 9 | if not nums: 10 | return [''] 11 | 12 | ans = [] 13 | for i in range(1, len(nums) + 1): 14 | words = get_words(nums[i:]) 15 | if nums[:i] in DICT: 16 | for char in DICT[nums[:i]]: 17 | for item in words: 18 | ans.append(char + item) 19 | 20 | return ans 21 | 22 | 23 | print(get_words('12')) 24 | print(get_words('221')) 25 | print(get_words('1')) 26 | print(get_words('2212')) 27 | -------------------------------------------------------------------------------- /lottery-ticket/description.md: -------------------------------------------------------------------------------- 1 | # Lottery ticket 2 | 3 | Your favorite uncle, Morty, is crazy about the lottery and even crazier about how he picks his “lucky” numbers. And even though his “never fail” strategy has yet to succeed, Uncle Morty doesn't let that get him down. 4 | 5 | Every week he searches through the Sunday newspaper to find a string of digits that might be potential lottery picks. But this week the newspaper has moved to a new electronic format, and instead of a comfortable pile of papers, Uncle Morty receives a text file with the stories. 6 | 7 | Help your Uncle find his lotto picks. Given a large series of number strings, return each that might be suitable for a lottery ticket pick. Note that a valid lottery ticket must have 7 unique numbers between 1 and 59, digits must be used in order, and every digit must be used exactly once. 8 | 9 | ## Example 10 | 11 | ### Input 12 | 13 | "569815571556", "4938532894754", "1234567", "472844278465445" 14 | 15 | ### Output 16 | 17 | 4938532894754 -> 49 38 53 28 9 47 54 18 | 1234567 -> 1 2 3 4 5 6 7 19 | 20 | ## Run the program 21 | 22 | In the folder run the command: 23 | 24 | ``` 25 | python lottery-ticket.py 26 | ``` 27 | -------------------------------------------------------------------------------- /lottery-ticket/lottery-ticket.py: -------------------------------------------------------------------------------- 1 | def lotto_picks_util(nums, idx, remaining, seen): 2 | if idx >= len(nums): 3 | if remaining == 0: 4 | return [[]] 5 | else: 6 | return [] 7 | elif remaining == 1 and idx == len(nums) - 1: 8 | if int(nums[idx]) > 0: 9 | return [[nums[idx]]] 10 | else: 11 | return [] 12 | elif int(nums[idx]) == 0 or len(nums) - idx > 2 * remaining: 13 | return [] 14 | 15 | picks = [] 16 | for i in range(1, 3): 17 | if int(nums[idx:idx + i]) < 60 and nums[idx:idx + i] not in seen: 18 | seen.add(nums[idx:idx + i]) 19 | for pick in lotto_picks_util(nums, idx + i, remaining - 1, seen): 20 | picks.append([nums[idx:idx + i]] + pick) 21 | seen.remove(nums[idx:idx + i]) 22 | 23 | return picks 24 | 25 | 26 | def print_lotto_picks(nums, ans): 27 | if not nums: 28 | print('{} ->'.format('None')) 29 | 30 | for num, picks in zip(nums, ans): 31 | result = '' 32 | for idx, pick in enumerate(picks): 33 | if idx > 0: 34 | result += ', ' 35 | result += ' '.join(pick) 36 | print('{} -> {}'.format(num, result)) 37 | 38 | print 39 | 40 | 41 | def lotto_picks(nums): 42 | ans = [] 43 | for num in nums: 44 | if not num.isdigit(): 45 | ans.append([]) 46 | else: 47 | seen = set() 48 | ans.append(lotto_picks_util(num, 0, 7, seen)) 49 | 50 | return ans 51 | 52 | 53 | if __name__ == "__main__": 54 | # Test empty input 55 | print_lotto_picks([], lotto_picks([])) 56 | 57 | # Test no picks for input 58 | print_lotto_picks(['123456789012345'], lotto_picks(['123456789012345'])) 59 | 60 | # Test duplicate numbers in input 61 | print_lotto_picks(['1111111'], lotto_picks(['1111111'])) 62 | 63 | # Test input took short for lotto_picks 64 | print_lotto_picks(['12345'], lotto_picks(['12345'])) 65 | 66 | # Test invaliud input 67 | print_lotto_picks(['a1234567'], lotto_picks(['a1234567'])) 68 | 69 | # Test one pick for input 70 | print_lotto_picks(['1234567'], lotto_picks(['1234567'])) 71 | 72 | # Test multiple options for input 73 | print_lotto_picks(['15342615'], lotto_picks(['15342615'])) 74 | 75 | # Test multiple inputs 76 | print_lotto_picks( 77 | ['1234567', '2345678'], lotto_picks(['1234567', '2345678'])) 78 | 79 | # Test inputs given in question 80 | input = ['569815571556', '4938532894754', '1234567', '472844278465445'] 81 | print_lotto_picks(input, lotto_picks(input)) 82 | -------------------------------------------------------------------------------- /median-stream/median-stream.py: -------------------------------------------------------------------------------- 1 | from random import randint 2 | 3 | 4 | def find_median(array): 5 | if not array: 6 | return None 7 | 8 | smallest = float('inf') 9 | largest = float('-inf') 10 | count = 0 11 | 12 | for num in array: 13 | count += 1 14 | smallest = min(smallest, num) 15 | largest = max(largest, num) 16 | 17 | median = count // 2 18 | guess = (largest + smallest) // 2 19 | 20 | while smallest <= largest: 21 | running_median = 0 22 | num_equals = 0 23 | for num in array: 24 | if num < guess: 25 | running_median += 1 26 | elif num == guess: 27 | num_equals += 1 28 | 29 | if running_median <= median: 30 | if num_equals > 0 and running_median + num_equals > median: 31 | return guess 32 | smallest = guess + 1 33 | else: 34 | largest = guess - 1 35 | guess = (largest + smallest) // 2 36 | 37 | return smallest 38 | 39 | 40 | print(find_median([])) 41 | 42 | print(find_median([1, 2, 3, 5, 8])) 43 | print(find_median([8, 2, 1, 5, 3])) 44 | 45 | print(find_median([1, 1, 1, 2, 2, 2, 8])) 46 | print(find_median([1, 1, 1, 2, 2, 2, 8, 9, 10, 11])) 47 | 48 | print(find_median([8, 8, 1, 8, 8, 1])) 49 | print(find_median([8, 8, 8, 8, 8, 8])) 50 | print(find_median([1, 1, 1, 1, 1, 1])) 51 | print(find_median([2**31 - 1, 2**31 - 1, 2 ** 52 | 31 - 1, 2**31 - 1, 2**31 - 1, 2**31 - 1])) 53 | print(find_median([-2**31, -2**31, -2**31, -2**31, -2**31, -2**31])) 54 | 55 | print(find_median([1])) 56 | 57 | elements = [randint(1, 100) for _ in range(100)] 58 | sorted_elements = sorted(elements) 59 | print('Expected median: {}'.format(sorted_elements[len(elements)//2])) 60 | print('Median fn: {}'.format(find_median(elements))) 61 | -------------------------------------------------------------------------------- /min-num-boats/min-num-boats.py: -------------------------------------------------------------------------------- 1 | # weight the boat can carry 190kg 2 | # max 2 people per boat 3 | # list of peoples weights [20, 30, 40, 60, 60, 90] 4 | 5 | """ 6 | 90 7 | 60 + 20 8 | 60 + 30 9 | 40 10 | 11 | 90 12 | 60 13 | 60 + 20 14 | 40 + 30 15 | 16 | 90 + 20 17 | 60 + 30 18 | 60 + 40 19 | """ 20 | 21 | 22 | def min_num_boats(max_weight, people): 23 | if not people: 24 | return 0 25 | 26 | if max_weight <= 0: 27 | raise Exception('invalid max weight') 28 | 29 | min_num = 0 30 | left = 0 31 | right = len(people) - 1 32 | while left <= right: 33 | currentWeight = people[right] 34 | if currentWeight > max_weight: 35 | raise Exception('boat not heavy enough for person') 36 | 37 | right -= 1 38 | if currentWeight + people[left] <= max_weight: 39 | left += 1 40 | min_num += 1 41 | 42 | return min_num 43 | 44 | 45 | weight = 100 46 | people = [20, 30, 40, 60, 80, 90] 47 | print(min_num_boats(weight, people)) 48 | -------------------------------------------------------------------------------- /num-complements/num-complements.py: -------------------------------------------------------------------------------- 1 | # l = [2, 1, 3, 4], k = 2; num of complements 2 2 | # l = [4, 1, 3, 2], k = 2; num of complements 2 3 | 4 | 5 | def numComplements(l, k): 6 | seen = set() 7 | counter = 0 8 | 9 | for num in l: 10 | if num in seen: 11 | counter += 1 12 | 13 | seen.add(num + k) 14 | seen.add(num - k) 15 | 16 | return counter 17 | 18 | 19 | print(numComplements([22, 21, 23, 24], 2)) 20 | print(numComplements([24, 21, 23, 22], 2)) 21 | print(numComplements([2, 1, 3, 4], 2)) 22 | print(numComplements([2, 1, 3, 4], 1)) 23 | print(numComplements([2, 1, 3, 4], 0)) 24 | print(numComplements([2, 1, 3, 4, -1], 2)) 25 | -------------------------------------------------------------------------------- /num-islands/description.md: -------------------------------------------------------------------------------- 1 | # Number of islands 2 | 3 | Let's define a system for representing geographical maps as a 2D array comprised of 0s and 1s, where 0 represents "water" and 1 represents "land". For example: 4 | 5 | Please write a method that takes the 2D "map" array as an input and returns the number of islands on the map as the output. 6 | 7 | ## Example 8 | 9 | ### Input 10 | 11 | 0 0 0 0 0 0 0 12 | 0 1 0 0 0 0 0 13 | 1 1 1 0 1 0 0 14 | 0 1 1 0 1 0 0 15 | 0 0 0 0 0 0 0 16 | 0 0 1 1 1 0 0 17 | 0 0 1 1 0 0 0 18 | 19 | ### Output 20 | 21 | 3 islands 22 | 23 | ## Run the program 24 | 25 | In the folder run the command: 26 | 27 | ``` 28 | python num_islands.py 29 | ``` 30 | -------------------------------------------------------------------------------- /num-islands/num-islands.py: -------------------------------------------------------------------------------- 1 | directions = [[1, 0], [-1, 0], [0, 1], [0, -1]] 2 | 3 | 4 | def dfs(map, row, col): 5 | if row < 0 or row >= len(map) or \ 6 | col < 0 or col >= len(map[row]) or \ 7 | map[row][col] == 0: 8 | return None 9 | 10 | map[row][col] = 0 11 | for r, c in directions: 12 | dfs(map, row + r, col + c) 13 | 14 | return None 15 | 16 | 17 | def num_islands(map): 18 | if not map or not map[0]: 19 | return 0 20 | 21 | islands = 0 22 | for row in range(len(map)): 23 | for col in range(len(map[row])): 24 | if map[row][col] == 1: 25 | dfs(map, row, col) 26 | islands += 1 27 | 28 | return islands 29 | -------------------------------------------------------------------------------- /pattern-match/description.md: -------------------------------------------------------------------------------- 1 | # Pattern match 2 | 3 | Given a list of words and a string containing characters, return **true** or **false** depending on if the characters in the string match the pattern in the sentence. 4 | 5 | ## Example 6 | 7 | ### Input 8 | 9 | **words:** blue yellow green 10 | **code:** abc 11 | 12 | ### Output 13 | 14 | true 15 | 16 | ## Run the program 17 | 18 | In the folder run the command: 19 | 20 | ``` 21 | node pattern-match.js 22 | ``` 23 | -------------------------------------------------------------------------------- /pattern-match/pattern-match.js: -------------------------------------------------------------------------------- 1 | function patternMatch(string1, string2) { 2 | const words = string1.split(' '); 3 | const chars = string2.split(''); 4 | 5 | const wordsMap = new Map(); 6 | const charsMap = new Set(); 7 | 8 | let wordsPtr = 0; 9 | let charsPtr = 0; 10 | 11 | while (wordsPtr < words.length && charsPtr < chars.length) { 12 | if (wordsMap.has(words[wordsPtr])) { 13 | if (wordsMap.get(words[wordsPtr]) !== chars[charsPtr]) { 14 | return false; 15 | } 16 | } else if (charsMap.has(chars[charsPtr])) { 17 | return false; 18 | } else { 19 | wordsMap.set(words[wordsPtr], chars[charsPtr]); 20 | charsMap.add(chars[charsPtr]); 21 | } 22 | wordsPtr++; 23 | charsPtr++; 24 | } 25 | 26 | return true; 27 | } -------------------------------------------------------------------------------- /pattern-match/pattern-match.py: -------------------------------------------------------------------------------- 1 | def pattern_match(words, code): 2 | words_list = words.split(' ') 3 | code_list = list(code) 4 | if (len(words_list) != len(code_list)): 5 | return False 6 | 7 | char_map = {} 8 | word_map = set() 9 | for word, char in zip(words_list, code_list): 10 | if char in char_map: 11 | if char_map[char] != word: 12 | return False 13 | elif word in word_map: 14 | return False 15 | else: 16 | char_map[char] = word 17 | word_map.add(word) 18 | 19 | return True 20 | 21 | 22 | if __name__ == "__main__": 23 | words = 'blue yellow green' 24 | code = 'abc' 25 | print(pattern_match(words, code)) 26 | -------------------------------------------------------------------------------- /pig-latin/description.md: -------------------------------------------------------------------------------- 1 | # Valid parenthesis 2 | 3 | Given a sentence, convert each word to pig latin and output the convertd sentence. 4 | 5 | **Rules:** 6 | 7 | 1. Move the consonant cluster from the start of the word to the end of the word. 8 | 2. When words begin on a vowel, simply add "-yay", "-way", or "-ay" to the end instead. 9 | 10 | ## Example 11 | 12 | **Input:** Hello world!! 13 | **Output:** Ellohay, orldway!! 14 | 15 | ## Run the program 16 | 17 | In the folder run the command: 18 | 19 | ``` 20 | python pig-latin.py 21 | ``` 22 | -------------------------------------------------------------------------------- /pig-latin/pig-latin.py: -------------------------------------------------------------------------------- 1 | def move_first_char(word, capitalize): 2 | vowels = {'a', 'e', 'i', 'o', 'u'} 3 | if word[0] in vowels: 4 | return word + 'ay' 5 | elif len(word) > 1 and word[:2].lower() == 'qu': 6 | if capitalize: 7 | return word[2:].capitalize() + word[:2].lower() + 'ay' 8 | else: 9 | return word[2:] + word[:2] + 'ay' 10 | else: 11 | idx = 0 12 | while word[idx] not in vowels: 13 | idx += 1 14 | 15 | if capitalize: 16 | return word[idx:].capitalize() + word[:idx].lower() + 'ay' 17 | else: 18 | return word[idx:] + word[:idx] + 'ay' 19 | 20 | 21 | def pig_latin(word): 22 | if not word: 23 | return '' 24 | 25 | if len(word) == 1 and word[0].isalpha(): 26 | return word + 'ay' 27 | 28 | # punctuation 29 | suffix_ptr = len(word) - 1 30 | while not word[suffix_ptr].isalpha(): 31 | suffix_ptr -= 1 32 | 33 | prefix = word[:suffix_ptr + 1] 34 | suffix = word[suffix_ptr + 1:] 35 | 36 | is_upper = prefix[0].isupper() 37 | return move_first_char(prefix, is_upper) + suffix 38 | 39 | 40 | def pig_latin_sentence(sentence): 41 | phrase = [] 42 | for word in sentence.split(' '): 43 | phrase.append(pig_latin(word)) 44 | 45 | return ' '.join(phrase) 46 | 47 | 48 | print pig_latin_sentence('Hello, world!!') 49 | print pig_latin_sentence('eat apples') 50 | print pig_latin_sentence('quick brown fox') 51 | -------------------------------------------------------------------------------- /print-articles/print-articles.py: -------------------------------------------------------------------------------- 1 | """ 2 | Input: 3 | { 4 | "articles": [ 5 | { 6 | "text": "This is a short article." 7 | }, 8 | { 9 | "text": "Now for a longer article. This one has a lot of text." 10 | }, 11 | { 12 | "text": "Another article with medium length." 13 | } 14 | ], 15 | "width": 55 16 | } 17 | 18 | Output: 19 | +-------------------------------------------------------+ 20 | |This is a short article. | 21 | +-------------------------------------------------------+ 22 | |Now for a longer article. This one has a lot of text. | 23 | +-------------------------------------------------------+ 24 | |Another article with medium length. | 25 | +-------------------------------------------------------+ 26 | 27 | +------------+ 28 | |This is a | 29 | |short | 30 | |article. | 31 | +------------+ 32 | |Now for a | 33 | |longer | 34 | |article. | 35 | |This one has| 36 | |a lot of | 37 | |text. | 38 | +------------+ 39 | |Another | 40 | |article with| 41 | |medium | 42 | |length. | 43 | +------------+ 44 | 45 | """ 46 | 47 | 48 | class Article: 49 | def __init__(self, text): 50 | self.text = text 51 | 52 | 53 | articles = [ 54 | Article("This is a short article."), 55 | Article("Now for a longer article. This one has a lot of text."), 56 | Article("Wonderland is another article with medium length.") 57 | ] 58 | 59 | width = 10 60 | 61 | 62 | def printBorder(width): 63 | dashes = '-' * width 64 | print('+{}+'.format(dashes)) 65 | 66 | 67 | def calcCurrentWidth(currentWords): 68 | currentWidth = len(' '.join(currentWords)) 69 | if currentWidth > 0: 70 | return currentWidth + 1 71 | return 0 72 | 73 | 74 | def printCurrent(currentWords, width): 75 | text = ' '.join(currentWords) 76 | print('|{message: <{fill}}|'.format( 77 | message=text, fill=(width))) 78 | 79 | 80 | def printArticles(articles, width): 81 | printBorder(width) 82 | 83 | current = [] 84 | 85 | for article in articles: 86 | words = article.text.split(' ') 87 | for word in words: 88 | if calcCurrentWidth(current) + len(word) > width: 89 | printCurrent(current, width) 90 | current = [word] 91 | else: 92 | current.append(word) 93 | 94 | if current: 95 | printCurrent(current, width) 96 | current = [] 97 | 98 | printBorder(width) 99 | 100 | 101 | printArticles(articles, width) 102 | -------------------------------------------------------------------------------- /print-columns/print-columns.py: -------------------------------------------------------------------------------- 1 | """ 2 | Input: 3 | 6 4 | / \ 5 | 3 4 6 | / \ \ 7 | 5 1 0 8 | \ / 9 | 2 8 10 | / \ 11 | 9 7 12 | 13 | Output: 5 9 3 2 6 1 7 4 8 0 14 | """ 15 | 16 | 17 | def printColumns(root): 18 | if not root: 19 | return 20 | 21 | queue = [(root, 0)] 22 | columns = {} 23 | 24 | while queue: 25 | tempq = [] 26 | for node, column in queue: 27 | if column not in columns: 28 | columns[column] = [] 29 | columns[column].append(node.val) 30 | 31 | if node.left: 32 | tempq.append((node.left, column - 1)) 33 | 34 | if node.right: 35 | tempq.append((node.right, column + 1)) 36 | 37 | queue = tempq 38 | 39 | ans = [] 40 | for column in sorted(columns.keys()): 41 | ans.extend(columns[column]) 42 | print(ans) 43 | 44 | 45 | class Node: 46 | def __init__(self, val, left=None, right=None): 47 | self.val = val 48 | self.left = left 49 | self.right = right 50 | 51 | 52 | nine = Node(9) 53 | seven = Node(7) 54 | two = Node(2, nine, seven) 55 | five = Node(5, None, two) 56 | one = Node(1) 57 | three = Node(3, five, one) 58 | eight = Node(8) 59 | zero = Node(0, eight) 60 | four = Node(4, None, zero) 61 | six = Node(6, three, four) 62 | 63 | printColumns(six) 64 | -------------------------------------------------------------------------------- /priority-expiry-cache/priority-expiry-cache.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | 4 | class LinkedListNode: 5 | def __init__(self, key): 6 | # Key: the key inserted into the cache 7 | self.key = key 8 | self.next = None 9 | self.prev = None 10 | 11 | 12 | class LinkedList: 13 | def __init__(self): 14 | self.head = LinkedListNode(-1) 15 | self.tail = LinkedListNode(-1) 16 | 17 | self.head.next = self.tail 18 | self.tail.prev = self.head 19 | 20 | 21 | class BinarySearchTree: 22 | def __init__(self): 23 | self.root = None 24 | 25 | # Gets the earliest expiry time or lowest priority 26 | def getMinValueNode(self): 27 | current = self.root 28 | 29 | # loop down to find the leftmost leaf 30 | while current and current.left: 31 | current = current.left 32 | 33 | return current 34 | 35 | 36 | class ExpireTimeNode: 37 | def __init__(self, time, keys=set()): 38 | # ExpireTime of the entry 39 | self.time = time 40 | # Set of keys with the expireTime 41 | self.keys = keys 42 | self.left = None 43 | self.right = None 44 | 45 | def removeKeyInNode(self): 46 | # removes arbitrary key from the list of keys 47 | key = self.keys.pop() 48 | if not self.keys: 49 | self.deleteNode() 50 | return key 51 | 52 | def deleteKeyInNode(self, key): 53 | self.keys.remove(key) 54 | if not self.keys: 55 | self.deleteNode() 56 | 57 | def deleteNode(self): 58 | # Removes the Node from the BST 59 | pass 60 | 61 | 62 | class PriorityNode: 63 | def __init__(self, priority, lru={}): 64 | # Priority of the entry 65 | self.priority = priority 66 | # LRU Linked List Map: key is the key interested into the cache, value is a LinkedListNode 67 | self.lru = lru 68 | # Linked List: linked list to keep track of the head and tail of the lru linked list 69 | self.linkedList = LinkedList() 70 | self.left = None 71 | self.right = None 72 | 73 | def deleteKeyInNode(self, key): 74 | llNode = self.lru[key] 75 | llNode.prev.next = llNode.next 76 | llNode.next.prev = llNode.prev 77 | del self.lru[key] 78 | if not self.lru: 79 | self.deleteNode() 80 | 81 | def deleteNode(self): 82 | # Removes the Node from the BST 83 | pass 84 | 85 | 86 | class PriorityExpiryCache: 87 | def __init__(self, maxItems): 88 | self.maxItems = maxItems 89 | # Cache (map): key is the key inserted into the cache, value is an object with the value, priority and expireTime 90 | self.cache = {} 91 | # Expire Time BST: ordered based on the expire time 92 | self.expireTimeTree = BinarySearchTree() 93 | # Priority BST: ordered based on the priority 94 | self.priorityTree = BinarySearchTree() 95 | 96 | def evictItem(self): 97 | keyToDelete = None 98 | earliestExpiryTimeNode = self.expireTimeTree.getMinValueNode() 99 | if earliestExpiryTimeNode.key < int(time.time()): 100 | keyToDelete = earliestExpiryTimeNode.removeKeyInNode() 101 | 102 | keyPriority = self.cache[keyToDelete].priority 103 | 104 | priorityNode = self.priorityTree.getKeyNode(keyPriority) 105 | priorityNode.deleteKeyInNode(keyToDelete) 106 | else: 107 | lowestPriorityNode = self.priorityTree.getMinValueNode() 108 | keyToDelete = lowestPriorityNode.linkedList.tail.key 109 | priorityNode.deleteKeyInNode(keyToDelete) 110 | 111 | keyExpireTime = self.cache[keyToDelete].expireTime 112 | 113 | expireTimeNode = self.expireTimeTree.getKeyNode(keyExpireTime) 114 | expireTimeNode.deleteKeyInNode(keyToDelete) 115 | 116 | del self.cache[keyToDelete] 117 | 118 | def evictItems(self): 119 | while len(self.cache.keys()) > self.maxItems: 120 | self.evictItem() 121 | -------------------------------------------------------------------------------- /rat-race/rat-race.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Libs included: 3 | underscore lodash chai sinon sinon-chai mocha async request q bluebird jsdom 4 | 5 | 3 mice: "Mouse marathon" 26 miles 6 | mouse 1: runs 1 mph 7 | mouse 2: runs 2 mph 8 | mouse 3: runs 3 mph 9 | 10 | 3 random starting points along the marathon race path 11 | 0 ... 26 12 | 13 | Find the probability of which each mouse will win 14 | mouse 1: 40% 15 | mouse 2: 30% 16 | mouse 3: 30% 17 | 18 | Mouse 1 will win if 19 | d1 / 1mph = time it takes for mouse 1 to finish(t1) 20 | t1 < t2 and t1 < t3 21 | 22 | d1 = d2 / 2 23 | d1 = d3 / 3 24 | 25 | d3 = 26 26 | d1 = 26 / 3 27 | d2 = (26 / 3) * 2 28 | 29 | m3 m2 m1 30 | 26 17.3 8.6 31 | 32 | t2 = d2 / 2mph 33 | t3 = d3 / 3mph 34 | ''' 35 | 36 | 37 | function mouseMarathon(numRaces, mouseSpeeds) { 38 | const MAX_DISTANCE = 26 39 | const MIN_DISTANCE = 0 40 | 41 | const speeds = [...mouseSpeeds].sort() 42 | const numWins = speeds.map(speed= > 0) 43 | 44 | for (let i=0 45 | i < numRaces 46 | i++) { 47 | const positions = [] 48 | speeds.forEach(speed=> { 49 | const random=(Math.random() * (MAX_DISTANCE - MIN_DISTANCE)) + MIN_DISTANCE 50 | positions.push(random) 51 | }) 52 | positions.sort() 53 | 54 | const timesToFinish = speeds.map((speed, idx)=> { 55 | return positions[idx] / speed 56 | }) 57 | 58 | let winningTime = Number.MAX_SAFE_INTEGER 59 | let winningIdx = -1 60 | 61 | timesToFinish.forEach((time, idx)=> { 62 | if (time < winningTime) { 63 | winningTime=time 64 | winningIdx=idx 65 | } 66 | }) 67 | 68 | numWins[winningIdx]++ 69 | } 70 | 71 | return numWins.map(wins= > (wins / numRaces) * 100) 72 | } 73 | 74 | console.log(mouseMarathon(100, [1, 2, 3])) 75 | -------------------------------------------------------------------------------- /reverse-div-three.py/reverse-div-three.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers like the following: 3 | 4 | [1, 6, 3, 8, 9] 5 | 6 | Reverse the order of the integers in the array, but only those divisible by 3, while keeping all the other integers in the same positions as before. E.g. 7 | 8 | [1, 9, 3, 8, 6] 9 | """ 10 | 11 | 12 | def reverseDivThree(array): 13 | left = 0 14 | right = len(array) - 1 15 | 16 | while left < right: 17 | if array[left] % 3 != 0: 18 | left += 1 19 | elif array[right] % 3 != 0: 20 | right -= 1 21 | else: 22 | array[left], array[right] = array[right], array[left] 23 | left += 1 24 | right -= 1 25 | 26 | return array 27 | 28 | 29 | print(reverseDivThree([1, 6, 3, 8, 9])) 30 | print(reverseDivThree([15, 3, 2, 0, 7, -3, 5])) 31 | print(reverseDivThree([-3, 3, 9, 12])) 32 | print(reverseDivThree([1, 2, 4, 5, 7])) 33 | -------------------------------------------------------------------------------- /reverse-string-brackets/reverse-string-brackets.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string with valid brackets (could have multiple nested brackets), 3 | reverse the contents of the brackets and return the string with the reversed 4 | content and no brackets 5 | """ 6 | 7 | 8 | def reverseChars(chars, left, right): 9 | while left < right: 10 | chars[left], chars[right] = chars[right], chars[left] 11 | left += 1 12 | right -= 1 13 | 14 | 15 | def reverseStringBrackets(string): 16 | if not string: 17 | return '' 18 | 19 | chars = list(string) 20 | stack = [] 21 | for idx, char in enumerate(chars): 22 | if char == '(': 23 | stack.append(idx) 24 | elif char == ')': 25 | left = stack.pop() 26 | reverseChars(chars, left + 1, idx - 1) 27 | 28 | return ''.join(filter(lambda s: s not in {'(', ')'}, chars)) 29 | 30 | 31 | print(reverseStringBrackets('(Hello)World')) 32 | print(reverseStringBrackets('World(Hello)')) 33 | print(reverseStringBrackets('((HelloWorld))')) 34 | print(reverseStringBrackets('(HelloWorld)')) 35 | print(reverseStringBrackets('(Hello)(World)')) 36 | print(reverseStringBrackets('(Hello(World)Good)')) 37 | -------------------------------------------------------------------------------- /shortest-sublist-threshold/shortest-sublist-threshold.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a list of positive numbers and a threshold. 3 | Find the shortest sub list which sum up to greater than the threshold 4 | """ 5 | 6 | 7 | def shortestThreshold(nums, threshold): 8 | if not nums: 9 | return [] 10 | 11 | left = right = 0 12 | current = 0 13 | minList = (float('inf'), -1, -1) 14 | 15 | while right < len(nums): 16 | current += nums[right] 17 | 18 | while current >= threshold and left <= right: 19 | if right - left + 1 < minList[0]: 20 | minList = (right - left + 1, left, right + 1) 21 | 22 | current -= nums[left] 23 | left += 1 24 | 25 | right += 1 26 | 27 | while current >= threshold and left < right: 28 | if right - left < minList[0]: 29 | minList = (right - left, left, right) 30 | 31 | current -= nums[left] 32 | left += 1 33 | 34 | return nums[minList[1]:minList[2]] 35 | 36 | 37 | print(shortestThreshold([3, 5, 2], 10)) 38 | print(shortestThreshold([4, 1, 3, 5, 2, 1, 8], 10)) 39 | print(shortestThreshold([3, 5, 2, 1, 9], 10)) 40 | print(shortestThreshold([9, 1, 3, 5, 2], 10)) 41 | print(shortestThreshold([3, 5, 1, 9, 10], 10)) 42 | print(shortestThreshold([3, 5, 10, 1, 9], 10)) 43 | print(shortestThreshold([10, 3, 5, 1, 9], 10)) 44 | -------------------------------------------------------------------------------- /smallest-common-num/smallest-common-num.py: -------------------------------------------------------------------------------- 1 | """ 2 | Problem: Find smallest common number in list of sorted arrays. 3 | e.g. array1: [1, 3, 5, 10, 20] array2: [2, 4, 5, 10, 20] array3: [2, 4, 10, 20] 4 | common elements = > 10 & 20 result = > 10 5 | Constraints: 6 | * Any number of arrays 7 | * Each array could be of any size 8 | * [execution time limit] 4 seconds(js) 9 | 10 | 10 11 | 10 12 | 10 13 | """ 14 | 15 | 16 | def smallest_common_num(arrays): 17 | idxs = [0] * len(arrays) 18 | 19 | largest_num = float('-inf') 20 | largest_arrays_idxs = set() 21 | 22 | while len(largest_arrays_idxs) != len(arrays): 23 | for idx, array in enumerate(arrays): 24 | if idxs[idx] >= len(array): 25 | return None 26 | 27 | if array[idxs[idx]] > largest_num: 28 | largest_num = array[idxs[idx]] 29 | largest_arrays_idxs = {idx} 30 | elif array[idxs[idx]] == largest_num: 31 | largest_arrays_idxs.add(idx) 32 | 33 | for idx in range(len(idxs)): 34 | if idx not in largest_arrays_idxs: 35 | idxs[idx] += 1 36 | 37 | return largest_num 38 | 39 | 40 | print(smallest_common_num([[1, 3, 5, 10, 20], 41 | [1, 2, 4, 5, 10, 20], 42 | [2, 4, 10, 20]])) 43 | -------------------------------------------------------------------------------- /subarray-sum/description.md: -------------------------------------------------------------------------------- 1 | Input: List(1, 5, 3, 6, -1, 13, 5) 2 | ^ ^ 3 | Input: targetSum 18 4 | Output: startIndex (inclusive), endIndex (exclusive) 5 | 6 | 1, -> 6, 9, 12, 18 7 | targetSum = 0 8 | [1,1] 9 | 10 | # Two Sum 11 | 12 | Given an array of integers, return indices of the subarray such that they add up to a specific target. 13 | 14 | ## Example 15 | 16 | ### Input: 17 | 18 | nums = [1, 5, 3, 6, -1, 13, 5] 19 | target = 18 20 | 21 | ### Output: 22 | 23 | **startIndex (inclusive), endIndex (exclusive)** 24 | [1,1] 25 | 26 | ## Run the program 27 | 28 | In the folder run the command: 29 | 30 | ``` 31 | python subarray-sum.py 32 | ``` 33 | -------------------------------------------------------------------------------- /subarray-sum/subarray-sum.py: -------------------------------------------------------------------------------- 1 | def subarray_sum(nums, target): 2 | map = {} 3 | sum = 0 4 | ans = [] 5 | 6 | for i in range(len(nums)): 7 | if sum not in map: 8 | map[sum] = [i] 9 | else: 10 | map[sum].append(i) 11 | 12 | if sum - target in map: 13 | ans.extend([[start, i] for start in map[sum - target]]) 14 | sum += nums[i] 15 | 16 | if sum - target in map: 17 | ans.extend([[start, len(nums)] for start in map[sum - target]]) 18 | 19 | return ans 20 | 21 | 22 | print(subarray_sum([1, 5, 3, 6, -1, 13, 5], 18)) 23 | print(subarray_sum([1, 5, 3, 6, -1, 13, 5], 0)) 24 | print(subarray_sum([1, 5, 3, 6, -1, 13, 5], 9)) 25 | print(subarray_sum([], 0)) 26 | print(subarray_sum([1, 5, 3, 6, -1, 13, 60], 60)) 27 | -------------------------------------------------------------------------------- /task-scheduler/task-scheduler.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | from heapq import heapify, heappush, heappop 3 | 4 | 5 | def leastInterval(tasks, n): 6 | min_heap = [] 7 | queue = deque([(0, '0') for _ in range(n)]) 8 | 9 | tasks_map = {} 10 | for task in tasks: 11 | if task not in tasks_map: 12 | tasks_map[task] = 1 13 | else: 14 | tasks_map[task] += 1 15 | 16 | min_heap = [(-num, task) for task, num in tasks_map.items()] 17 | heapify(min_heap) 18 | 19 | done_tasks = 0 20 | num_cycles = 0 21 | while done_tasks < len(tasks): 22 | if min_heap: 23 | num, task = heappop(min_heap) 24 | queue.append((num + 1, task)) 25 | done_tasks += 1 26 | else: 27 | queue.append((0, '0')) 28 | 29 | cooled_task = queue.popleft() 30 | if cooled_task[0] < 0: 31 | heappush(min_heap, cooled_task) 32 | 33 | num_cycles += 1 34 | 35 | return num_cycles 36 | 37 | 38 | print(leastInterval(["A", "A", "A", "B", "B", "B"], 2)) 39 | -------------------------------------------------------------------------------- /validate-number/validate-number.py: -------------------------------------------------------------------------------- 1 | """ 2 | "123" True 3 | "-1.23" True 4 | "abc" False 5 | "1.1.1" False 6 | "1,000" False 7 | ".54" True 8 | "1a" False 9 | "+234" False 10 | "1." True 11 | "1-1" False 12 | ".5 4" False 13 | " .54 " False 14 | "" False 15 | "-" False 16 | "." False 17 | """ 18 | 19 | 20 | def isValidNumber(s): 21 | if not s or (len(s) == 1 and not s.isdigit()): 22 | return False 23 | 24 | has_decimal = False 25 | 26 | for idx, char in enumerate(s): 27 | if char == '-': 28 | if idx != 0: 29 | return False 30 | elif char == '.': 31 | if has_decimal: 32 | return False 33 | has_decimal = True 34 | elif not char.isdigit(): 35 | return False 36 | 37 | return True 38 | 39 | 40 | strings = [ 41 | "123", 42 | "-1.23", 43 | "abc", 44 | "1.1.1", 45 | "1,000", 46 | ".54", 47 | "1a", 48 | "+234", 49 | "1.", 50 | "1-1", 51 | ".5 4", 52 | " .54 ", 53 | "", 54 | "-", 55 | ".", 56 | ] 57 | 58 | for s in strings: 59 | print(isValidNumber(s)) 60 | -------------------------------------------------------------------------------- /validate-parenthesis/description.md: -------------------------------------------------------------------------------- 1 | # Valid parenthesis 2 | 3 | Given a string containing the characters '(' and ')' return the least modified valid string of parenthesis by removing parenthesis. 4 | 5 | An input string is valid if: 6 | 7 | 1. Open brackets must be closed by the same type of brackets. 8 | 2. Open brackets must be closed in the correct order. 9 | 3. Note that an empty string is also considered valid. 10 | 11 | ## Example 12 | 13 | **Input:** "().()" 14 | **Output:** "().()" 15 | 16 | **Input:** "())())" 17 | **Output:** "()()" 18 | 19 | ## Run the program 20 | 21 | In the folder run the command: 22 | 23 | ``` 24 | python validate-parenthesis.py 25 | ``` 26 | -------------------------------------------------------------------------------- /validate-parenthesis/validate-parenthesis.py: -------------------------------------------------------------------------------- 1 | def validate_parenthesis(input): 2 | stack = [] 3 | temp = input 4 | for idx, char in enumerate(temp): 5 | if char == '(': 6 | stack.append((char, idx)) 7 | elif char == ')': 8 | if stack and stack[-1][0] == '(': 9 | # remove from input 10 | stack.pop() 11 | else: 12 | stack.append((char, idx)) 13 | 14 | # Valid input 15 | if not stack: 16 | return input 17 | 18 | ans = [] 19 | remove = set([idx for char, idx in stack]) 20 | for idx, char in enumerate(input): 21 | if idx not in remove: 22 | ans.append(char) 23 | 24 | return ''.join(ans) 25 | 26 | 27 | print(validate_parenthesis('()')) 28 | print(validate_parenthesis('())())')) 29 | print(validate_parenthesis('())))')) 30 | print(validate_parenthesis('().(()')) 31 | print(validate_parenthesis(')')) 32 | print(validate_parenthesis('((()')) 33 | -------------------------------------------------------------------------------- /validate-xml/validate-xml.py: -------------------------------------------------------------------------------- 1 | # 2 | # Complete the 'validate_xml' function below. 3 | # 4 | # The function is expected to return a STRING. 5 | # The function accepts STRING xml as parameter. 6 | # 7 | 8 | 9 | def get_tag(xml, idx): 10 | tag = '' 11 | next_idx = idx + 1 12 | while xml[next_idx] != '>' or next_idx >= len(xml): 13 | if next_idx >= len(xml) or xml[next_idx] == '<': 14 | return '', next_idx 15 | 16 | tag += xml[next_idx] 17 | next_idx += 1 18 | 19 | return tag, next_idx + 1 20 | 21 | 22 | def validate_xml(xml): 23 | # Write your code here 24 | stack = [] 25 | idx = 0 26 | while idx < len(xml): 27 | if xml[idx] == '<': 28 | if idx + 1 >= len(xml): 29 | return 'parse error' 30 | elif xml[idx + 1] == '/': 31 | closing_tag, next_idx = get_tag(xml, idx + 1) 32 | if not closing_tag: 33 | return 'parse error' 34 | elif not stack or stack[-1] != closing_tag: 35 | return 'encountered closing tag without matching open tag for '.format(closing_tag) 36 | else: 37 | stack.pop() 38 | else: 39 | opening_tag, next_idx = get_tag(xml, idx) 40 | if not opening_tag: 41 | return 'parse error' 42 | stack.append(opening_tag) 43 | idx = next_idx 44 | else: 45 | idx += 1 46 | 47 | if stack: 48 | return 'missing closing tag for <{}>'.format(stack[-1]) 49 | 50 | return 'valid' 51 | 52 | 53 | if __name__ == '__main__': 54 | print(validate_xml('text')) 55 | -------------------------------------------------------------------------------- /word-exists/word-exists.py: -------------------------------------------------------------------------------- 1 | def exist(board, word): 2 | """ 3 | :type board: List[List[str]] 4 | :type word: str 5 | :rtype: bool 6 | """ 7 | def dfs(row, col, position): 8 | letter = board[row][col] 9 | board[row][col] = '#' 10 | 11 | for ro, co in [(1, 0), (-1, 0), (0, 1), (0, -1)]: 12 | nr = ro + row 13 | nc = co + col 14 | 15 | if nr < 0 or nr >= len(board) or nc < 0 or nc >= len(board[row]): 16 | continue 17 | 18 | if board[nr][nc] != word[position + 1]: 19 | continue 20 | 21 | if position + 1 == len(word) - 1 or dfs(nr, nc, position + 1): 22 | return True 23 | 24 | board[row][col] = letter 25 | return False 26 | 27 | for row in range(len(board)): 28 | for col in range(len(board[row])): 29 | if board[row][col] == word[0] and dfs(row, col, 0): 30 | return True 31 | 32 | return False 33 | 34 | 35 | print(exist([["A", "B"]], "AB")) 36 | --------------------------------------------------------------------------------