├── README.md ├── checkSerialization ├── README.md └── preorderSerializationCheck.py ├── countingIslandsProblem ├── countingInversions.py └── dfsSolution.py ├── dynamicProgramming └── dynamicProgramming.py ├── interactiveExamples ├── counting_trees.py └── tree_to_linked_list.py ├── nestedIntervals └── nestedIntervals.py ├── regex ├── README.md └── regex.py └── slidingWindow └── slidingwindow.py /README.md: -------------------------------------------------------------------------------- 1 | # TechnicalInterviewCodeSnippets 2 | Code snippets to go along with an on-campus technical interview presentation I made 3 | 4 | [Presentation here](https://jeremyaguilon.me/blog/visualizing_four_key_interview_algorithms) 5 | 6 | # Found a bug? 7 | 8 | You are likely correct! These snippets were hastily made. Feel free to make a pull request. 9 | -------------------------------------------------------------------------------- /checkSerialization/README.md: -------------------------------------------------------------------------------- 1 | ###Question: Verify Preorder Serialization of a Binary Tree 2 | 3 | You are given an array of strings, where each element is either a number (i.e. '13') or a sentinel value ('#'). 4 | If # represents a null element, return whether the array is a valid preorder serialization of a BST. 5 | The binary tree has no particular orderin (it's not necessarily a BST). 6 | 7 | Examples 8 | ``` 9 | [3,#,#] 10 | 11 | output: True 12 | 3 13 | / \ 14 | # # 15 | would serialize into the above array 16 | ``` 17 | 18 | ``` 19 | [3,4,5,#,6,#,2,#,#] 20 | output: True 21 | 22 | 3 23 | / \ 24 | 4 2 25 | / \ / \ 26 | 5 ## # 27 | / \ 28 | # 6 29 | would serialize into the above array 30 | ``` 31 | 32 | ``` 33 | [3] 34 | output: False 35 | Leaf nodes (nodes with no chidlren) clearly need 2 null pointers after, so it's easy to see that this 36 | isn't a valid serialization. 37 | ``` 38 | -------------------------------------------------------------------------------- /checkSerialization/preorderSerializationCheck.py: -------------------------------------------------------------------------------- 1 | def isValidSerialization(preorder): 2 | strings = preorder.split(",") 3 | stack = [] 4 | for s in strings: 5 | stack.append(s) 6 | shouldCascade = True 7 | while (shouldCascade): 8 | if len(stack) < 3: 9 | shouldCascade = False 10 | else: 11 | top_1 = stack.pop() 12 | top_2 = stack.pop() 13 | top_3 = stack.pop() 14 | shouldCascade = top_1 == '#' and top_2 == '#' and top_3 != '#' 15 | 16 | if not shouldCascade: 17 | stack.append(top_3) 18 | stack.append(top_2) 19 | stack.append(top_1) 20 | else: 21 | stack.append('#') 22 | return len(stack) == 1 and stack.pop() == '#' 23 | test = isValidSerialization("9,3,4,#,#,1,#,#,2,#,6,#,#") 24 | print(test) #True 25 | 26 | test = isValidSerialization("9,#,#,1") 27 | print(test) #False 28 | 29 | -------------------------------------------------------------------------------- /countingIslandsProblem/countingInversions.py: -------------------------------------------------------------------------------- 1 | def solution(arr): 2 | return countInversions(arr) 3 | 4 | def countInversions(arr): 5 | 6 | if len(arr) == 0 or len(arr) == 1: 7 | return 0 8 | 9 | # recursive case 10 | middle = len(arr) // 2 11 | left = arr[0:middle] 12 | right = arr[middle:] 13 | 14 | total = countInversions(left) + countInversions(right) 15 | 16 | i = 0 17 | pLeft = 0 18 | pRight = 0 19 | 20 | while (pLeft < len(left) and pRight < len(right)): 21 | if left[pLeft] <= right[pRight]: 22 | arr[i] = left[pLeft] 23 | pLeft += 1 24 | else: 25 | total += len(left) - pLeft 26 | arr[i] = right[pRight] 27 | pRight += 1 28 | i += 1 29 | while (pLeft < len(left)): 30 | arr[i] = left[pLeft] 31 | pLeft += 1 32 | i += 1 33 | while (pRight < len(right)): 34 | arr[i] = right[pRight] 35 | pRight += 1 36 | i += 1 37 | return total 38 | import random 39 | arr = [random.randint(0, 100) for i in range(100)] 40 | print(solution(arr)) 41 | print(arr) 42 | 43 | -------------------------------------------------------------------------------- /countingIslandsProblem/dfsSolution.py: -------------------------------------------------------------------------------- 1 | def solution(arr): 2 | total = 0 3 | for y in range(len(arr)): 4 | for x in range(len(arr[y])): 5 | if arr[y][x] == 1: 6 | total += 1 7 | dfs(x,y,arr) 8 | return total 9 | 10 | def dfs(x, y, arr): 11 | if y < 0 or y >= len(arr) or x < 0 or x >= len(arr[y]): 12 | return 13 | if arr[y][x] == 0: 14 | return 15 | arr[y][x] = 0 16 | dfs(x+1, y, arr) 17 | dfs(x-1, y, arr) 18 | dfs(x, y-1, arr) 19 | dfs(x, y+1, arr) 20 | 21 | print(solution([[1,1,1],[1,0,0],[0,1,0]])) #2 -------------------------------------------------------------------------------- /dynamicProgramming/dynamicProgramming.py: -------------------------------------------------------------------------------- 1 | def solution(n, coins): 2 | ascendingCoins = sorted(list(coins), reverse=True) 3 | total = 0 4 | for coin in ascendingCoins: 5 | total += solve(n - coin, ascendingCoins, coin) 6 | return total 7 | 8 | cache = {} 9 | 10 | def solve(n, coins, lastCoin): 11 | if (n, lastCoin) in cache: 12 | return cache[(n, lastCoin)] 13 | if n == 0: 14 | return 1 15 | if n < 0: 16 | return 0 17 | total = 0 18 | for coin in coins: 19 | if coin <= lastCoin: 20 | total += solve(n - coin, coins, coin) 21 | cache[(n, lastCoin)] = total 22 | return total 23 | 24 | def solveWithoutCache(n, coins, lastCoin): 25 | if n == 0: 26 | return 1 27 | if n < 0: 28 | return 0 29 | total = 0 30 | for coin in coins: 31 | if coin <= lastCoin: 32 | total += solveWithoutCache(n - coin, coins, coin) 33 | return total 34 | 35 | print(solution(15, {1,5})) # 4 ways 36 | print(solution(1500, {150, 200, 300, 5, 20, 21, 51, 24, 35, 60, 23})) # won't terminate without cache 37 | -------------------------------------------------------------------------------- /interactiveExamples/counting_trees.py: -------------------------------------------------------------------------------- 1 | # Given an int n, return the number of possible trees with n nodes you can construct 2 | # Example: n = 1 --> 1, the single node 3 | # n = 2 --> 2, a parent node with a left child and a parent node with a right child 4 | 5 | def solution(n): 6 | pass 7 | -------------------------------------------------------------------------------- /interactiveExamples/tree_to_linked_list.py: -------------------------------------------------------------------------------- 1 | # Given the root `Node` of a tree, convert the tree into a double linked list. 2 | # We don't particularly care about the order, but the linked list should contain 3 | # all the nodes inside the tree. 4 | 5 | class Node(object): 6 | def __init__(self, val, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | def __str__(self): 12 | return self.val 13 | 14 | def solution(root): 15 | if root is None: 16 | return root 17 | if root.left is None and root.right is None: 18 | return root 19 | 20 | stack = [] 21 | stack.append(root) 22 | 23 | head = root 24 | tail = None 25 | 26 | while len(stack) > 0: 27 | curr = stack.pop() 28 | 29 | if curr.left is not None: 30 | stack.append(curr.left) 31 | if curr.right is not None: 32 | stack.append(curr.right) 33 | 34 | if tail is None: 35 | tail = curr 36 | tail.left = None 37 | else: 38 | tail.right = curr 39 | curr.left = tail 40 | tail = curr 41 | tail.right = None 42 | return head 43 | -------------------------------------------------------------------------------- /nestedIntervals/nestedIntervals.py: -------------------------------------------------------------------------------- 1 | def solution(string): 2 | stack = [] 3 | for letter in string: 4 | if isOpeningBracket(letter): 5 | stack.append(letter) 6 | elif isClosingBracket(letter): 7 | if len(stack) == 0: 8 | return False 9 | lastOpener = stack.pop() 10 | if not matches(letter, lastOpener): 11 | return False 12 | return len(stack) == 0 13 | 14 | def isOpeningBracket(letter): 15 | return letter in {'{', '(', '['} 16 | 17 | def isClosingBracket(letter): 18 | return letter in {'}', ')', ']'} 19 | 20 | def matches(closer, opener): 21 | openToClose = {'{':'}', '[':']', '(':')'} 22 | return openToClose[opener] == closer 23 | 24 | print(solution("(3+9{12+4})(25)")) # true 25 | print(solution("3+9{12+4})(25)")) # false 26 | -------------------------------------------------------------------------------- /regex/README.md: -------------------------------------------------------------------------------- 1 | #Question: Basic Regex Matcher 2 | 3 | Create a basic regex function that returns true if a `string` matches a `pattern`. This particular 4 | regex language only has 2 special characters, `.` and `*`. 5 | 6 | * `.` Matches any individual character, one time. The empty string *does not* match `.` 7 | * `*` Matches any number of characters, *including* the empty string. 8 | 9 | Examples: 10 | 11 | ``` 12 | string: 'foobar' 13 | pattern: '*' 14 | output: True, since * matches everything 15 | ``` 16 | 17 | ``` 18 | string: 'foobar' 19 | pattern: 'fo.bar' 20 | output: True, since . matches the second o and everything else matches. 21 | ``` 22 | 23 | ``` 24 | string: 'foobar' 25 | pattern: '*ob.z' 26 | output: False 27 | ``` 28 | -------------------------------------------------------------------------------- /regex/regex.py: -------------------------------------------------------------------------------- 1 | def solution(string, pattern): 2 | solution = [[False] * (len(string)+1) for _ in range(len(pattern)+1)] 3 | solution[0][0] = True 4 | for i in range(1, len(string)+1): 5 | solution[0][i] = True 6 | 7 | for i in range(1, len(pattern)+1): 8 | # as long as pattern is the empty string, let it match 9 | solution[i][0] = solution[i-1][0] if pattern[i-1] == '*' else False 10 | for i in range(1, len(pattern) + 1): 11 | for j in range(1, len(string) + 1): 12 | if matches(pattern[i - 1], string[j - 1]): 13 | solution[i][j] = solution[i-1][j-1] 14 | elif pattern[i - 1] == "*": 15 | solution[i][j] = True 16 | else: 17 | solution[i][j] = False 18 | return solution[len(pattern)][len(string)] 19 | 20 | def matches(char1, char2): 21 | return char1 == '.' or char2 == '.' or char1==char2 22 | 23 | print(solution("str", "st.*")) 24 | print(solution("street", "s*at")) 25 | -------------------------------------------------------------------------------- /slidingWindow/slidingwindow.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a string and a set of characters, return the **smallest** substring that contains all of the characters in the set 3 | ''' 4 | 5 | def solution(string, char_set): 6 | # Step 1 and 2 7 | left, right, best_score = 0, 0, float('inf') 8 | 9 | # Step 3a: Generally, for sliding window, you often need a set or hashmap to track 10 | # the characters/values you have in your substring/subarray 11 | # Step 3b: This is an auxiliary value that lets us cleanly look up the characters 12 | # in char_set that we have found 13 | letter_map = {} # maps from character to number of occurences in the substring 14 | characters_encountered = 0 # when this is equal to len(char_set), we have a 15 | # candidate substring 16 | # Step 4 17 | while right < len(string): 18 | curr_right = string[right] 19 | 20 | # Step 5 21 | if curr_right in char_set: 22 | letter_map[curr_right] = letter_map.get(curr_right, 0) + 1 23 | if letter_map[curr_right] == 1: 24 | characters_encountered += 1 25 | right += 1 26 | 27 | # Step 6: If you have a new candidate substring (in this case we found all 28 | # our letters, begin incrementing left until it is *invalid* 29 | if (characters_encountered == len(char_set)): 30 | while characters_encountered == len(char_set): 31 | curr_left = string[left] 32 | if curr_left in char_set: 33 | letter_map[curr_left] -= 1 34 | if letter_map[curr_left] == 0: 35 | characters_encountered -= 1 36 | left += 1 37 | # Step 7: Finally! Update the best score if we have a new best. 38 | # This new candidate substring is bounded by right - left + 1. Avoid 39 | # off-by-one's by drawing an example out. 40 | best_score = min(best_score, right - left + 1) 41 | return best_score 42 | 43 | 44 | print(solution("adddddbcbba", {'a','b','c'})) # should be 4 45 | print(solution("abc", {'a','b','c'})) # should be 3 46 | print(solution("abdddddcbeba", {'a', 'b', 'c'})) # should be 5 47 | print(solution("abweweffawefcaaaaboiwuroqiwuroiueeeb", {'a', 'b', 'c'})) # should be 6 48 | --------------------------------------------------------------------------------