├── .gitignore ├── Problem 1-30 ├── problem_10.py ├── problem_11_autocompletion.py ├── problem_12.py ├── problem_13.py ├── problem_14.py ├── problem_15.py ├── problem_16.py ├── problem_17.py ├── problem_18.py ├── problem_19.py ├── problem_1_two_sum.py ├── problem_2.py ├── problem_20.py ├── problem_21.py ├── problem_22.py ├── problem_23.py ├── problem_24.py ├── problem_25_regular_expression_matching.py ├── problem_26.py ├── problem_27.py ├── problem_28.py ├── problem_29.py ├── problem_30.py ├── problem_3_serializer.py ├── problem_4.py ├── problem_5.py ├── problem_6.py ├── problem_7.py ├── problem_8.py └── problem_9.py ├── Problem 31-60 ├── problem_31.py ├── problem_32.py ├── problem_33.py ├── problem_34.py ├── problem_35.py └── problem_36.py ├── Problem Descriptions.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /Problem 1-30/problem_10.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Apple. 3 | 4 | Implement a job scheduler which takes in a function f and an integer n, and 5 | calls f after n milliseconds. 6 | ''' 7 | 8 | ''' 9 | EdgeCases: 10 | * Imagine a case, where (A,10) task A is scheduled to run after 10 seconds 11 | * and then when at 3rd second, another task B comes where (B,2) seconds 12 | * then which one would be executed first ? 13 | 14 | A more sophisticated edge case is, if two items receive the same absolute time, 15 | is it required to maintain order of insertion when running? Might be relevant 16 | in some use cases. The mentioned edge case, is obvious. at 5 task B runs, at 10 17 | task A runs. 18 | ''' 19 | 20 | ''' 21 | Solution: 22 | 1) calculate absolute times when a task get's added 23 | 2) push it into a priority queue with smallest absolute on top (binary heap) 24 | 3) have a runner that polls the queue once in a time interval (e.g. second) and 25 | checks if top task is to be executed, pop items from the heap that need to 26 | be executed. 27 | 4) now, the question is, how long does the run take? can I execute it 28 | synchronously or will this delay the scheduler? I could as well span into a 29 | thread pool to call run there. 30 | 31 | Also refer to following URL: 32 | https://pymotw.com/3/sched/ 33 | ''' 34 | -------------------------------------------------------------------------------- /Problem 1-30/problem_11_autocompletion.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Twitter. 3 | 4 | Implement an autocomplete system. That is, given a query string s and a set of 5 | all possible query strings, return all strings in the set that have s as a prefix. 6 | 7 | For example, given the query string de and the set of strings [dog, deer, deal], 8 | return [deer, deal]. 9 | 10 | Hint: Try preprocessing the dictionary into a more efficient data structure to 11 | speed up queries. 12 | ''' 13 | from collections import defaultdict 14 | 15 | class Trie_Node(object): 16 | def __init__(self, char=None): 17 | self.char = char 18 | self.children = defaultdict(Trie_Node) 19 | self.end_of_word = False 20 | 21 | 22 | def add(trie_root, word): 23 | cur_node = trie_root 24 | for char in word: 25 | if char in cur_node.children: 26 | cur_node = cur_node.children[char] 27 | else: 28 | new_node = Trie_Node(char) 29 | cur_node.children[char] = new_node 30 | cur_node = new_node 31 | cur_node.end_of_word = True 32 | 33 | 34 | def search(trie_root, pattern): 35 | ''' 36 | Args: 37 | trie_root(Trie_Node): the root of the Trie tree 38 | pattern(string): the query string for autocomplete 39 | Returns: 40 | list: a list of possible results 41 | ''' 42 | cur_node = trie_root 43 | res = list() 44 | for char in pattern: 45 | if char in cur_node.children: # able to auto-complete 46 | cur_node = cur_node.children[char] 47 | res.append(char) 48 | else: # no matching 49 | return [] 50 | 51 | prefix = ''.join(res[:-1]) 52 | suffix = build_str(cur_node) # recursively find the suffix 53 | return [prefix + item for item in suffix] 54 | 55 | 56 | def build_str(trie_node): 57 | ''' 58 | Args: 59 | trie_node(Trie_Node): the node in the Trie that deeper than the pattern 60 | Returns: 61 | list: a list of sub_string of possible suffix 62 | ''' 63 | if trie_node.end_of_word: 64 | return [trie_node.char] 65 | 66 | sub_string = [] 67 | for k, v in trie_node.children.items(): 68 | sub_string.extend(build_str(v)) 69 | 70 | sub_string = [trie_node.char + item for item in sub_string] 71 | return sub_string 72 | 73 | 74 | def main(): 75 | root = Trie_Node('*') 76 | str_list = ['dog', 'deer', 'deel', 'deat', 'dealete', 'deassase'] 77 | for word in str_list: 78 | add(root, word) 79 | print search(root, 'de') 80 | 81 | 82 | if __name__ == '__main__': 83 | main() 84 | -------------------------------------------------------------------------------- /Problem 1-30/problem_12.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Amazon. 3 | 4 | There exists a staircase with N steps, and you can climb up either 1 or 2 steps 5 | at a time. Given N, write a function that returns the number of unique ways you 6 | can climb the staircase. The order of the steps matters. 7 | 8 | For example, if N is 4, then there are 5 unique ways: 9 | 10 | 1, 1, 1, 1 11 | 2, 1, 1 12 | 1, 2, 1 13 | 1, 1, 2 14 | 2, 2 15 | 16 | What if, instead of being able to climb 1 or 2 steps at a time, you could climb 17 | any number from a set of positive integers X? For example, if X = {1, 3, 5}, you 18 | could climb 1, 3, or 5 steps at a time. 19 | ''' 20 | def cache(func): 21 | data = dict() 22 | def wrapper(N, X): 23 | if N in data: 24 | return data[N] 25 | else: 26 | data[N] = func(N, X) 27 | return data[N] 28 | return wrapper 29 | 30 | 31 | @cache 32 | def climb_up(N, X): 33 | ''' 34 | Dynamic Programming 35 | Args: 36 | N(int): a staircase with N steps 37 | X(list): steps that are allowed 38 | Returns: 39 | int: number of ways to get to the top of the staircase 40 | ''' 41 | if N <= 1: 42 | return 1 43 | 44 | num_ways = 0 45 | for step in X: 46 | if N >= step: 47 | num_ways += climb_up(N - step, X) 48 | return num_ways 49 | 50 | 51 | def main(): 52 | print climb_up(100, [1, 3, 5]) 53 | 54 | if __name__ == '__main__': 55 | main() 56 | -------------------------------------------------------------------------------- /Problem 1-30/problem_13.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Amazon. 3 | 4 | Given an integer k and a string s, find the length of the longest substring that 5 | contains at most k distinct characters. 6 | 7 | For example, given s = "abcba" and k = 2, the longest substring with k distinct 8 | characters is "bcb". 9 | ''' 10 | 11 | def solution(string, k): 12 | ''' 13 | Keep a window and add elements to the window till it contains less or equal 14 | k. If unique elements exceeds than required in window, start removing the 15 | elements from left side. 16 | 17 | Args: 18 | string(string) 19 | k(int) 20 | Returns: 21 | int: count of the length of the longest substring 22 | ''' 23 | table = dict() 24 | slow = -1 25 | fast = -1 26 | distinct_cnt = 0 27 | for idx, char in enumerate(string): # iter over every char 28 | if char in table: # hit in the table 29 | table[char] += 1 30 | fast = idx 31 | else: # miss, means this is a new distinct char 32 | if len(table) == k: # the table is full, have to move from left 33 | while len(table) != k - 1: 34 | slow += 1 35 | char_slow = string[slow] 36 | table[char_slow] -= 1 37 | if table[char_slow] == 0: 38 | table.pop(char_slow) 39 | table[char] = 1 40 | fast = idx 41 | else: # table is not full, directly add it in 42 | table[char] = 1 43 | fast = idx 44 | if fast - slow > distinct_cnt: 45 | distinct_cnt = fast - slow 46 | return distinct_cnt 47 | 48 | 49 | def solution2(s, k): 50 | ''' 51 | Thanks to Ricardo: 52 | https://github.com/r1cc4rdo/daily_coding_problem/blob/master/daily_coding_problem_11_15.py 53 | providing this wonderful concise solution. 54 | ''' 55 | assert(len(s) >= k) 56 | 57 | start_index, end_index, max_length = 0, k, k 58 | while end_index < len(s): 59 | 60 | end_index += 1 61 | while True: 62 | 63 | distinct_characters = len(set(s[start_index:end_index])) 64 | if distinct_characters <= k: 65 | break 66 | 67 | start_index += 1 68 | 69 | max_length = max(max_length, end_index - start_index) 70 | 71 | return max_length 72 | 73 | def main(): 74 | s = 'aabbcc' 75 | k = 3 76 | print solution2(s, k) 77 | 78 | if __name__ == '__main__': 79 | main() 80 | -------------------------------------------------------------------------------- /Problem 1-30/problem_14.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | ''' 3 | This problem was asked by Google. 4 | 5 | The area of a circle is defined as πr^2. Estimate π to 3 decimal places using a 6 | Monte Carlo method. 7 | 8 | Hint: The basic equation of a circle is x2 + y2 = r2. 9 | ''' 10 | import random 11 | import math 12 | 13 | random.seed(0xBADC0FFE) 14 | 15 | def est_pi(num): 16 | cnt = 0 17 | total = 0 18 | prev_pi, pi_approx = 0, 3 19 | 20 | while True: 21 | point = list() 22 | for i in range(num): 23 | point.append((random.random(), random.random())) 24 | if point[i][0] ** 2 + point[i][1] ** 2 <= 1: 25 | cnt += 1 26 | total += 1 27 | prev_pi = pi_approx 28 | pi_approx = 4 * cnt / float(total) 29 | print 'prev_pi = {}, pi_approx = {}'.format(prev_pi, pi_approx) 30 | if abs(prev_pi - pi_approx) < 1e-9: # assume we don't know math.pi 31 | return pi_approx 32 | # if abs(math.pi - pi_approx) < 1e-4: # assume math.pi is known 33 | # return pi_approx 34 | 35 | 36 | def main(): 37 | print est_pi(1000) 38 | 39 | 40 | if __name__ == '__main__': 41 | main() 42 | -------------------------------------------------------------------------------- /Problem 1-30/problem_15.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Facebook. 3 | 4 | Given a stream of elements too large to store in memory, pick a random element 5 | from the stream with uniform probability. 6 | ''' 7 | ''' 8 | Note: 9 | 10 | Let the current element's index be i. 11 | 12 | Choose to 'remember' the current element at probability 1/i. When EOF is reached, 13 | produced the element you remember. 14 | 15 | At the end, for each element with index i there is a probability to be chosen: 16 | 17 | https://stackoverflow.com/questions/23351918/select-an-element-from-a-stream-with-uniform-distributed-probability 18 | 19 | A formal prove can be done using induction, following these guidelines. 20 | ''' 21 | import random 22 | random.seed(0xBADC0FFE) 23 | 24 | def sample_gen_func(num): 25 | for x in xrange(num): 26 | yield x 27 | 28 | def solution(sample_generator): 29 | sample_count = 0 30 | selected_sample = None 31 | 32 | for sample in sample_generator: 33 | sample_count += 1 34 | if random.random() <= 1.0 / sample_count: 35 | selected_sample = sample 36 | 37 | return selected_sample 38 | 39 | def main(): 40 | num = 1000 41 | print solution(sample_gen_func(num)) 42 | 43 | if __name__ == '__main__': 44 | main() 45 | -------------------------------------------------------------------------------- /Problem 1-30/problem_16.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Twitter. 3 | 4 | You run an e-commerce website and want to record the last N order ids in a log. 5 | Implement a data structure to accomplish this, with the following API: 6 | 7 | record(order_id): adds the order_id to the log 8 | get_last(i): gets the ith last element from the log. i is guaranteed to be 9 | smaller than or equal to N. 10 | 11 | You should be as efficient with time and space as possible. 12 | ''' 13 | class OrdersLog(object): 14 | def __init__(self, num): 15 | self.circular_buffer = [None] * num 16 | self.current_index = 0 17 | 18 | def record(self, order_id): 19 | self.circular_buffer[self.current_index] = order_id 20 | self.current_index += 1 21 | if self.current_index == len(self.circular_buffer): 22 | self.current_index = 0 23 | 24 | def get_last(self, num): 25 | start_index = self.current_index - num 26 | if start_index < 0: # wrap around 27 | return (self.circular_buffer[start_index:] + 28 | self.circular_buffer[:self.current_index]) 29 | else: # no wrapping required 30 | return self.circular_buffer[start_index:self.current_index] 31 | 32 | 33 | def main(): 34 | N = 20 35 | log = OrdersLog(10) 36 | for id in xrange(35): 37 | log.record(id) 38 | 39 | assert(log.get_last(0) == []) 40 | assert(log.get_last(1) == [34]) 41 | assert(log.get_last(5) == range(30, 35)) 42 | 43 | if __name__ == '__main__': 44 | main() 45 | -------------------------------------------------------------------------------- /Problem 1-30/problem_17.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Google. 3 | 4 | Suppose we represent our file system by a string in the following manner: 5 | 6 | The string "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext" represents: 7 | 8 | dir 9 | subdir1 10 | subdir2 11 | file.ext 12 | The directory dir contains an empty sub-directory subdir1 and a sub-directory 13 | subdir2 containing a file file.ext. 14 | 15 | The string "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext" represents: 16 | 17 | dir 18 | subdir1 19 | file1.ext 20 | subsubdir1 21 | subdir2 22 | subsubdir2 23 | file2.ext 24 | The directory dir contains two sub-directories subdir1 and subdir2. subdir1 25 | contains a file file1.ext and an empty second-level sub-directory subsubdir1. 26 | subdir2 contains a second-level sub-directory subsubdir2 containing a file 27 | file2.ext. 28 | 29 | We are interested in finding the longest (number of characters) absolute path 30 | to a file within our file system. For example, in the second example above, 31 | the longest absolute path is "dir/subdir2/subsubdir2/file2.ext", and its length 32 | is 32 (not including the double quotes). 33 | 34 | Given a string representing the file system in the above format, return the 35 | length of the longest absolute path to a file in the abstracted file system. 36 | If there is no file in the system, return 0. 37 | 38 | Note: 39 | 40 | The name of a file contains at least a period and an extension. 41 | 42 | The name of a directory or sub-directory will not contain a period. 43 | ''' 44 | 45 | class Node(object): 46 | ''' 47 | Node of a Directory N-ary Tree 48 | ''' 49 | def __init__(self, val=None, level=None, parent=None, is_file=False): 50 | self.val = val 51 | self.level = level 52 | self.parent = parent 53 | self.subdir = list() # Node's children as a list 54 | self.is_file =is_file 55 | 56 | def add_node(self, node=None): 57 | self.subdir.append(node) 58 | 59 | def get_parent(self): 60 | return self.parent 61 | 62 | 63 | class Tree(object): 64 | ''' 65 | A Directory N-ary Tree 66 | ''' 67 | def __init__(self, root=None): 68 | self.root = Node('*', -1) 69 | 70 | 71 | def build_tree(path_str): 72 | ''' 73 | Build a directory n-ary tree 74 | Args: 75 | path_str(string): a string represented a fild system path 76 | Returns: 77 | Tree: a directory tree 78 | ''' 79 | path_dir = path_str.split('\n') 80 | dir_tree = Tree() 81 | cur_level = -1 82 | cur_root = dir_tree.root 83 | 84 | for token in path_dir: 85 | tabs = 0 86 | while token[tabs] == '\t': 87 | tabs += 1 88 | 89 | if cur_level >= tabs: # need to back track the parent node 90 | i = cur_level - tabs + 1 91 | while i != 0: 92 | cur_root = cur_root.get_parent() 93 | i -= 1 94 | 95 | if len(token.split('.')) > 1: # is a file 96 | new_node = Node(token[tabs:], tabs, cur_root, True) 97 | else: # not a file 98 | new_node = Node(token[tabs:], tabs, cur_root) 99 | 100 | cur_root.add_node(new_node) 101 | cur_level = tabs 102 | cur_root = new_node 103 | 104 | return dir_tree 105 | 106 | 107 | def lgst_file_path(node): 108 | ''' 109 | Given a tree node, find the longest absolute path to a file 110 | Args: 111 | node(Node): a tree node 112 | Returns: 113 | int: the length of the longest path 114 | ''' 115 | if node.is_file: # hit a leaf, and leaf is a file 116 | return len(node.val) 117 | if len(node.subdir) == 0: # hit a leaf but a dir 118 | return 0 119 | 120 | max_len = 0 121 | for sub_node in node.subdir: 122 | max_len = max(max_len, lgst_file_path(sub_node)) 123 | 124 | # node.level < 0 means this node is root 125 | length = max_len if node.level < 0 else max_len + len(node.val) + 1 126 | 127 | return length 128 | 129 | 130 | def main(): 131 | path_str = 'dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext' 132 | path_str_2 = ('dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext' + 133 | '\ndir2\n\tsubdir1\n\tsubdir2\n\t\tsubsubdir1\n\t\t\tsubsubsubdir3\n\t\t\t\tfile3.ext') 134 | tree = build_tree(path_str_2) 135 | print lgst_file_path(tree.root) 136 | 137 | if __name__ == '__main__': 138 | main() 139 | -------------------------------------------------------------------------------- /Problem 1-30/problem_18.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Google. 3 | 4 | Given an array of integers and a number k, where 1 <= k <= length of the array, 5 | compute the maximum values of each subarray of length k. 6 | 7 | For example, given array = [10, 5, 2, 7, 8, 7] and k = 3, we should get: 8 | [10, 7, 8, 8], since: 9 | 10 | 10 = max(10, 5, 2) 11 | 7 = max(5, 2, 7) 12 | 8 = max(2, 7, 8) 13 | 8 = max(7, 8, 7) 14 | 15 | Do this in O(n) time and O(k) space. You can modify the input array in-place and 16 | you do not need to store the results. You can simply print them out as you 17 | compute them. 18 | 19 | Reference: 20 | https://www.geeksforgeeks.org/sliding-window-maximum-maximum-of-all-subarrays-of-size-k/ 21 | ''' 22 | from __future__ import print_function 23 | from collections import deque 24 | 25 | # A Deque (Double ended queue) based 26 | # method for printing maximum element 27 | # of all subarrays of size k 28 | def printMax(arr, n, k): 29 | '''Create a Double Ended Queue, q that will store indexes of array elements. 30 | The queue will store indexes of useful elements in every window and it will 31 | maintain decreasing order of values from front to rear in q, i.e., 32 | arr[q.front[]] to arr[q.rear()] are sorted in decreasing order. 33 | 34 | Args: 35 | arr(list): input array of integers 36 | n(int): length of input array 37 | k(int): window size 38 | 39 | Returns: 40 | None 41 | ''' 42 | q = deque() 43 | 44 | # Process first k (or first window) elements of array 45 | for i in range(k): 46 | 47 | # For every element, the previous smaller elements are useless so remove 48 | # them from q 49 | while q and arr[i] >= arr[q[-1]] : 50 | q.pop() 51 | 52 | # Add new element at rear of queue 53 | q.append(i) 54 | 55 | # Process rest of the elements, i.e. from arr[k] to arr[n-1] 56 | for i in range(k, n): 57 | 58 | # The element at the front of the queue is the largest element of 59 | # previous window, so print it 60 | print(str(arr[q[0]]) + " ", end = "") 61 | 62 | # Remove the elements which are out of this window 63 | while q and q[0] <= i-k: 64 | # remove from front of deque 65 | q.popleft() 66 | 67 | # Remove all elements smaller than the currently being added element 68 | # (Remove useless elements) 69 | while q and arr[i] >= arr[q[-1]] : 70 | q.pop() 71 | 72 | # Add current element at the rear of q 73 | q.append(i) 74 | 75 | # Print the maximum element of last window 76 | print(str(arr[q[0]])) 77 | 78 | 79 | def main(): 80 | test_arr = [10, 5, 2, 7, 8, 7] 81 | k = 3 82 | printMax(test_arr, len(test_arr), k) 83 | 84 | 85 | if __name__ == '__main__': 86 | main() 87 | -------------------------------------------------------------------------------- /Problem 1-30/problem_19.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Facebook. 3 | 4 | A builder is looking to build a row of N houses that can be of K different 5 | colors. He has a goal of minimizing cost while ensuring that no two neighboring 6 | houses are of the same color. 7 | 8 | Given an N by K matrix where the nth row and kth column represents the cost to 9 | build the nth house with kth color, return the minimum cost which achieves this 10 | goal. 11 | ''' 12 | def solution(costs): 13 | ''' 14 | DP by adding a house at a time 15 | Args: 16 | costs(list of list) 17 | Returns: 18 | int 19 | ''' 20 | best_cost = [0] * len(costs[0]) 21 | for cost in costs: # add a house at a time 22 | temp_cost = [0] * len(costs[0]) 23 | for index in xrange(len(cost)): 24 | # best cost is the one for that color plus min cost between every other color 25 | temp_cost[index] = cost[index] + min(best_cost[:index] + 26 | best_cost[index + 1:]) 27 | best_cost = temp_cost 28 | print best_cost 29 | 30 | return min(best_cost) 31 | 32 | 33 | def main(): 34 | costs = [[2, 1, 1], 35 | [1, 10, 3], 36 | [1, 2, 100]] 37 | print solution(costs) 38 | 39 | if __name__ == '__main__': 40 | main() 41 | -------------------------------------------------------------------------------- /Problem 1-30/problem_1_two_sum.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was recently asked by Google. 3 | 4 | Given a list of numbers and a number k, return whether any two numbers from the 5 | list add up to k. 6 | 7 | For example, given [10, 15, 3, 7] and k of 17, return true since 10 + 7 is 17. 8 | 9 | Bonus: Can you do this in one pass? 10 | ''' 11 | 12 | # from sets import Set # deprecated, now use 'set' directly 13 | 14 | def solution(list_nums, target): 15 | ''' 16 | Use a hash set to store the number we have seen. Then whenever we see a new 17 | number, check whether the difference of it and the target already in the 18 | hash set. 19 | 20 | Args: 21 | list_nums(list): a list of number 22 | target(int): the sum that is looked for 23 | 24 | returns: 25 | bool: whether there is a pair of numbers add up to target 26 | ''' 27 | num_seen_set = set() 28 | for num in list_nums: 29 | if target - num in num_seen_set: 30 | return True 31 | else: 32 | num_seen_set.add(num) 33 | return False 34 | 35 | 36 | def main(): 37 | test_list = [10, 15, 3, 7] 38 | k = 17 39 | print solution(test_list, k) 40 | 41 | 42 | if __name__ == '__main__': 43 | main() 44 | -------------------------------------------------------------------------------- /Problem 1-30/problem_2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Uber. 3 | 4 | Given an array of integers, return a new array such that each element at index i 5 | of the new array is the product of all the numbers in the original array except 6 | the one at i. 7 | 8 | For example, if our input was [1, 2, 3, 4, 5], the expected output would be 9 | [120, 60, 40, 30, 24]. If our input was [3, 2, 1], the expected output would be 10 | [2, 3, 6]. 11 | 12 | Follow-up: what if you can't use division? 13 | ''' 14 | 15 | def solution(list_nums): 16 | ''' 17 | Without using division, have to create a (k,v) dictionary to store the index 18 | and the multiplication result to the left of each num we see in first scan. 19 | Then create the new list by go from right to left in second run. At the same 20 | time, the multiplication to the right need to be stored. 21 | 22 | Args: 23 | list_nums(list): a list of numbers 24 | 25 | Returns: 26 | list: a new list 27 | ''' 28 | mul_left = dict() 29 | mul_right = dict() 30 | 31 | new_list = [None] * len(list_nums) # best practice: use None to initiate 32 | 33 | mul_left[-1] = 1 34 | for i in range(len(list_nums) - 1): 35 | mul_left[i] = list_nums[i] * mul_left[i - 1] 36 | 37 | mul_right[len(list_nums)] = 1 38 | for j in reversed(range(len(list_nums))[1:]): 39 | mul_right[j] = list_nums[j] * mul_right[j + 1] 40 | 41 | for i in range(len(list_nums)): 42 | new_list[i] = mul_left[i - 1] * mul_right[i + 1] 43 | 44 | return new_list 45 | 46 | def main(): 47 | list_nums = [1, 2, 3, 4, 5] 48 | # list_nums = [3, 2, 1] 49 | # list_nums = [] 50 | print solution(list_nums) 51 | 52 | if __name__ == '__main__': 53 | main() 54 | -------------------------------------------------------------------------------- /Problem 1-30/problem_20.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Google. 3 | 4 | Given two singly linked lists that intersect at some point, find the intersecting 5 | node. The lists are non-cyclical. 6 | 7 | For example, given A = 1 - > 3 -> 7 -> 8 -> 10 and B = 99 -> 1 -> 8 -> 10, 8 | return the node with value 8. 9 | 10 | In this example, assume nodes with the same value are the exact same node objects. 11 | 12 | Do this in O(M + N) time (where M and N are the lengths of the lists) and 13 | constant space. 14 | ''' 15 | class Node(object): 16 | def __init__(self, val=None, next=None): 17 | self.val = val 18 | self.next = next 19 | 20 | def add_node(self, node=None): 21 | self.next = node 22 | return node 23 | 24 | 25 | def find_intersection(A, B): 26 | ''' 27 | Find intersection of two singly list 28 | Args: 29 | A(Node) 30 | B(Node) 31 | Returns: 32 | Node: intersection node 33 | ''' 34 | while A.val != B.val: 35 | # if A runs to the end first, connect to B, and vice versa 36 | A = B if A.next == None else A.next 37 | B = A if B.next == None else B.next 38 | return A 39 | 40 | 41 | def main(): 42 | A = Node(1) 43 | B = Node(99) 44 | A.add_node(Node(3)).add_node(Node(7)).add_node(Node(8)).add_node(Node(10)) 45 | B.add_node(Node(99)).add_node(Node(1)).add_node(Node(8)).add_node(Node(10)) 46 | print find_intersection(A, B).val 47 | 48 | 49 | if __name__ == '__main__': 50 | main() 51 | -------------------------------------------------------------------------------- /Problem 1-30/problem_21.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Snapchat. 3 | 4 | Given an array of time intervals (start, end) for classroom lectures (possibly 5 | overlapping), find the minimum number of rooms required. 6 | 7 | For example, given [(30, 75), (0, 50), (60, 150)], you should return 2. 8 | ''' 9 | ''' 10 | Note: 11 | Minimum Number of Platforms Required for a Railway/Bus Station 12 | https://www.geeksforgeeks.org/minimum-number-platforms-required-railwaybus-station/ 13 | 14 | time type room_number 15 | 0 start 1 16 | 30 start 2 17 | 50 end 1 18 | 60 start 2 19 | 75 end 1 20 | 150 end 0 21 | ''' 22 | def find_min_rooms(time_list): 23 | ''' 24 | Args: 25 | time_list(list) 26 | Returns: 27 | int 28 | ''' 29 | start = sorted([num[0] for num in time_list]) 30 | end = sorted([num[1] for num in time_list]) 31 | 32 | room_occupied = max_room_num = 0 33 | i = j = 0 34 | n = len(time_list) 35 | 36 | while i < n and j < n: 37 | if start[i] < end[j]: 38 | room_occupied += 1 39 | max_room_num = max(room_occupied, max_room_num) 40 | i += 1 41 | else: 42 | room_occupied -= 1 43 | j += 1 44 | 45 | return max_room_num 46 | 47 | 48 | def main(): 49 | time_list = [(30, 75), (0, 50), (60, 150)] 50 | time_list2 = [(90,91), (94, 120), (95, 112), (110, 113), (150, 190), (180, 200)] 51 | print find_min_rooms(time_list2) 52 | 53 | if __name__ == '__main__': 54 | main() 55 | -------------------------------------------------------------------------------- /Problem 1-30/problem_22.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Microsoft. 3 | 4 | Given a dictionary of words and a string made up of those words (no spaces), 5 | return the original sentence in a list. If there is more than one possible 6 | reconstruction, return any of them. If there is no possible reconstruction, 7 | then return null. 8 | 9 | For example, given the set of words 'quick', 'brown', 'the', 'fox', and the 10 | string "thequickbrownfox", you should return ['the', 'quick', 'brown', 'fox']. 11 | 12 | Given the set of words 'bed', 'bath', 'bedbath', 'and', 'beyond', and the 13 | string "bedbathandbeyond", return either ['bed', 'bath', 'and', 'beyond] or 14 | ['bedbath', 'and', 'beyond']. 15 | ''' 16 | ''' 17 | Note: Wordbreak from Leetcode 18 | https://www.programcreek.com/2012/12/leetcode-solution-word-break/ 19 | https://www.programcreek.com/2014/03/leetcode-word-break-ii-java/ 20 | 21 | Deep copy a list in python: 22 | https://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list 23 | ''' 24 | 25 | class Node(object): 26 | def __init__(self, val=None, next_n=None): 27 | self.val = val 28 | self.next = next_n 29 | 30 | def reconstruct(string, dict_set): 31 | ''' 32 | Args: 33 | string(String) 34 | dict_set(Set) 35 | Returns: 36 | List 37 | ''' 38 | ptr = [None] * (len(string) + 1) 39 | 40 | for i in xrange(len(string)): # traverse each sub string 41 | for j in xrange(i, len(string) + 1): 42 | sub_string = string[i:j] 43 | if sub_string in dict_set: 44 | new_node = Node(sub_string) 45 | if not ptr[j]: 46 | ptr[j] = new_node 47 | else: 48 | add_at_tail(ptr[j], new_node) 49 | 50 | # testing: 51 | # ------------ 52 | # for item in ptr: 53 | # print ptr.index(item) 54 | # while item: 55 | # print item.val 56 | # item = item.next 57 | 58 | res = list() # final result 59 | curr = list() # current words found 60 | dfs(ptr, res, curr, len(ptr) - 1) # find out all combinations 61 | return res 62 | 63 | 64 | def add_at_tail(head, node): 65 | ''' 66 | Add at the end of the linked list 67 | Args: 68 | head(Node) 69 | node(Node) 70 | Returns: 71 | None 72 | ''' 73 | while head.next: 74 | head = head.next 75 | head.next = node 76 | 77 | 78 | def dfs(ptr, result, current, idx): 79 | ''' 80 | Args: 81 | ptr(List) 82 | result(List) 83 | current(List) 84 | idx(int) 85 | Returns: 86 | None 87 | ''' 88 | if idx == 0: # get to the beginning, dfs ends, add current to result 89 | result.append(current) # reversed: current[::-1] or list(reversed(current)) 90 | return 91 | 92 | if not ptr[idx]: # hit a None 93 | return 94 | else: # hit a word 95 | node = ptr[idx] 96 | while node: 97 | word = node.val 98 | # deepcopy: https://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list 99 | temp = current[:] 100 | temp.insert(0, word) # normally append(word) 101 | dfs(ptr, result, temp, idx - len(word)) 102 | node = node.next 103 | 104 | 105 | def main(): 106 | # dict_set = {'quick', 'brown', 'the', 'fox'} 107 | # string = 'thequickbrownfox' 108 | dict_set_2 ={'bed', 'bath', 'bedbath', 'and', 'beyond','dba'} 109 | string_2 = 'bedbathandbeyond' 110 | print reconstruct(string_2, dict_set_2) 111 | 112 | 113 | if __name__ == '__main__': 114 | main() 115 | -------------------------------------------------------------------------------- /Problem 1-30/problem_23.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Google. 3 | 4 | You are given an M by N matrix consisting of booleans that represents a board. 5 | Each True boolean represents a wall. Each False boolean represents a tile you 6 | can walk on. 7 | 8 | Given this matrix, a start coordinate, and an end coordinate, return the minimum 9 | number of steps required to reach the end coordinate from the start. If there is 10 | no possible path, then return null. You can move up, left, down, and right. You 11 | cannot move through walls. You cannot wrap around the edges of the board. 12 | 13 | For example, given the following board: 14 | 15 | [[f, f, f, f], 16 | [t, t, f, t], 17 | [f, f, f, f], 18 | [f, f, f, f]] 19 | 20 | and start = (3, 0) (bottom left) and end = (0, 0) (top left), the minimum number 21 | of steps required to reach the end is 7, since we would need to go through (1, 2) 22 | because there is a wall everywhere else on the second row. 23 | ''' 24 | ''' 25 | A* Algorithm: 26 | https://www.redblobgames.com/pathfinding/a-star/implementation.html 27 | 28 | def heuristic(a, b): 29 | (x1, y1) = a 30 | (x2, y2) = b 31 | return abs(x1 - x2) + abs(y1 - y2) 32 | 33 | def a_star_search(graph, start, goal): 34 | frontier = PriorityQueue() 35 | frontier.put(start, 0) 36 | came_from = {} 37 | cost_so_far = {} 38 | came_from[start] = None 39 | cost_so_far[start] = 0 40 | 41 | while not frontier.empty(): 42 | current = frontier.get() 43 | 44 | if current == goal: 45 | break 46 | 47 | for next in graph.neighbors(current): 48 | new_cost = cost_so_far[current] + graph.cost(current, next) 49 | if next not in cost_so_far or new_cost < cost_so_far[next]: 50 | cost_so_far[next] = new_cost 51 | priority = new_cost + heuristic(goal, next) 52 | frontier.put(next, priority) 53 | came_from[next] = current 54 | 55 | return came_from, cost_so_far 56 | ''' 57 | ''' 58 | Refer to: 59 | https://github.com/r1cc4rdo/daily_coding_problem/blob/master/daily_coding_problem_21_25.py 60 | ''' 61 | def find_shortest_path(map, start, end): 62 | coords = [(index_r, index_c) for index_r, row in enumerate(map) 63 | for index_c, element in enumerate(row) if not element] 64 | 65 | current_distance = 0 66 | distances = [[None for col in xrange(len(map[0]))] for row in xrange(len(map))] 67 | distances[start[0]][start[1]] = 0 68 | while True: 69 | 70 | wavefront = [coord for coord in coords if distances[coord[0]][coord[1]] == current_distance] 71 | if not wavefront: 72 | break 73 | 74 | current_distance += 1 75 | for node in wavefront: 76 | 77 | neighbours = [coord for coord in coords if (abs(node[0] - coord[0]) + abs(node[1] - coord[1])) == 1] 78 | for n in neighbours: 79 | if distances[n[0]][n[1]] is None: 80 | distances[n[0]][n[1]] = current_distance 81 | 82 | return distances[end[0]][end[1]] 83 | 84 | 85 | def main(): 86 | map = [[False, False, False, False], 87 | [True, True, False, True], 88 | [False, False, False, False], 89 | [False, False, False, False]] 90 | print find_shortest_path(map, (3, 0), (0, 0)) 91 | 92 | 93 | if __name__ == '__main__': 94 | main() 95 | -------------------------------------------------------------------------------- /Problem 1-30/problem_24.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Google. 3 | 4 | Implement locking in a binary tree. A binary tree node can be locked or unlocked 5 | only if all of its descendants or ancestors are not locked. 6 | 7 | Design a binary tree node class with the following methods: 8 | 9 | is_locked, which returns whether the node is locked 10 | 11 | lock, which attempts to lock the node. If it cannot be locked, then it should 12 | return false. Otherwise, it should lock it and return true. 13 | 14 | unlock, which unlocks the node. If it cannot be unlocked, then it should return 15 | false. Otherwise, it should unlock it and return true. 16 | 17 | You may augment the node to add parent pointers or any other property you would 18 | like. You may assume the class is used in a single-threaded program, so there is 19 | no need for actual locks or mutexes. Each method should run in O(h), where h is 20 | the height of the tree. 21 | ''' 22 | ''' 23 | Reference: 24 | https://www.dailycodingproblem.com/blog/lockable-binary-trees/ 25 | ''' 26 | 27 | class LockingBinaryTreeNode(object): 28 | def __init__(self, val, left=None, right=None, parent=None): 29 | self.val = val 30 | self.left = left 31 | self.right = right 32 | self.parent = parent 33 | self._is_locked = False 34 | self.locked_descendants_count = 0 35 | 36 | 37 | def _can_lock_or_unlock(self): 38 | if self.locked_descendants_count > 0: 39 | return False 40 | 41 | cur = self.parent 42 | while cur: 43 | if cur._is_locked: 44 | return False 45 | cur = cur.parent 46 | return True 47 | 48 | 49 | def is_locked(self): 50 | return self._is_locked 51 | 52 | 53 | def lock(self): 54 | if self._can_lock_or_unlock(): 55 | # Not locked, so update is_locked and increment count in all ancestors 56 | self._is_locked = True 57 | 58 | cur = self.parent 59 | while cur: 60 | cur.locked_descendants_count += 1 61 | cur = cur.parent 62 | return True 63 | else: 64 | return False 65 | 66 | 67 | def unlock(self): 68 | if self._can_lock_or_unlock(): 69 | self._is_locked = False 70 | 71 | # Update count in all ancestors 72 | cur = self.parent 73 | while cur: 74 | cur.locked_descendants_count -= 1 75 | cur = cur.parent 76 | return True 77 | else: 78 | return False 79 | -------------------------------------------------------------------------------- /Problem 1-30/problem_25_regular_expression_matching.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Facebook. 3 | 4 | Implement regular expression matching with the following special characters: 5 | 6 | . (period) which matches any single character 7 | * (asterisk) which matches zero or more of the preceding element 8 | 9 | That is, implement a function that takes in a string and a valid regular 10 | expression and returns whether or not the string matches the regular expression. 11 | 12 | For example, given the regular expression "ra." and the string "ray", your 13 | function should return true. The same regular expression on the string "raymond" 14 | should return false. 15 | 16 | Given the regular expression ".*at" and the string "chat", your function should 17 | return true. The same regular expression on the string "chats" should return false. 18 | ''' 19 | ''' 20 | Resource: 21 | Youtube: https://www.youtube.com/watch?v=l3hda49XcDE 22 | ''' 23 | 24 | def isMatch(self, s, p): 25 | m, n = len(s), len(p) 26 | DP = [[False]*(n+1) for i in range(m+1)] 27 | DP[0][0] = True 28 | for i in range(m+1): 29 | for j in range(1,n+1): 30 | if p[j-1] == '*': 31 | DP[i][j] = DP[i][j-2] or (i > 0 and j > 1 and (p[j-2] == '.' or 32 | s[i-1] == p[j-2]) and DP[i-1][j]) 33 | elif i > 0 and (p[j-1] == '.' or p[j-1] == s[i-1]): 34 | DP[i][j] = DP[i-1][j-1] 35 | return DP[m][n] 36 | 37 | 38 | def main(): 39 | s = 'ray' 40 | p = '.a.' 41 | print isMatch(s, p) 42 | 43 | 44 | if __name__ == '__main__': 45 | main() 46 | -------------------------------------------------------------------------------- /Problem 1-30/problem_26.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Google. 3 | 4 | Given a singly linked list and an integer k, remove the kth last element from 5 | the list. k is guaranteed to be smaller than the length of the list. 6 | 7 | The list is very long, so making more than one pass is prohibitively expensive. 8 | 9 | Do this in constant space and in one pass. 10 | ''' 11 | class Node(object): 12 | def __init__(self, val=None, next_n=None): 13 | self.val = val 14 | self.next = next_n 15 | 16 | def __str__(self): 17 | values = [] 18 | while self: 19 | values.append(str(self.val)) 20 | self = self.next 21 | return ' -> '.join(values) 22 | 23 | def add_node(self, node): 24 | self.next = node 25 | return node 26 | 27 | 28 | def remove_k_last_elem(head, k): 29 | ''' 30 | Use two pointers trick to access the kth last elem in one pass 31 | Args: 32 | head(Node): head of the linked list 33 | k(int) 34 | Returns: 35 | Node: head of the new linked list 36 | ''' 37 | slow = fast = head 38 | for _ in xrange(k): 39 | fast = fast.next 40 | 41 | while fast.next: 42 | slow = slow.next 43 | fast = fast.next 44 | 45 | slow.next = slow.next.next 46 | return head 47 | 48 | 49 | def main(): 50 | curr = head = Node(0) 51 | for i in xrange(1, 10): 52 | new_node = Node(i) 53 | curr = curr.add_node(new_node) 54 | 55 | print head 56 | remove_k_last_elem(head, 4) 57 | print head 58 | 59 | 60 | if __name__ == '__main__': 61 | main() 62 | -------------------------------------------------------------------------------- /Problem 1-30/problem_27.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Facebook. 3 | 4 | Given a string of round, curly, and square open and closing brackets, return 5 | whether the brackets are balanced (well-formed). 6 | 7 | For example, given the string "([])[]({})", you should return true. 8 | 9 | Given the string "([)]" or "((()", you should return false. 10 | ''' 11 | 12 | def is_balanced_method_2(brackets): 13 | ''' 14 | Reference: 15 | https://github.com/r1cc4rdo/daily_coding_problem/blob/master/daily_coding_problem_26_30.py#L35 16 | 17 | Note: 18 | reduce() accept 3 arguments: 19 | https://stackoverflow.com/questions/19589233/reduce-function-with-three-parameters 20 | The third argument is used as initializer 21 | 22 | The functools.reduce() documentation includes a Python version of the function: 23 | def reduce(function, iterable, initializer=None): 24 | it = iter(iterable) 25 | if initializer is None: 26 | value = next(it) 27 | else: 28 | value = initializer 29 | for element in it: 30 | value = function(value, element) 31 | return value 32 | ''' 33 | copy = None 34 | while brackets and brackets != copy: 35 | 36 | copy = brackets 37 | brackets = reduce(lambda s, p: s.replace(p, ''), ['()', '[]', '{}'], brackets) 38 | 39 | return brackets == '' 40 | 41 | 42 | def is_balanced(brackets): 43 | open_brackets = ['(', '[', '{'] 44 | close_brackets = [')', ']', '}'] 45 | dictionary = {')': '(', ']': '[', '}': '{'} 46 | 47 | br_stack = [] 48 | 49 | for br in brackets: 50 | if br in open_brackets: 51 | br_stack.append(br) 52 | elif br in close_brackets: 53 | if match(br_stack, br, dictionary): # balance 54 | br_stack.pop() 55 | else: 56 | return False 57 | else: 58 | raise ValueError('Invalid String.') 59 | 60 | if not br_stack: 61 | return True 62 | else: 63 | return False 64 | 65 | 66 | def match(br_list, br, dic): 67 | if not br_list: 68 | return False 69 | else: 70 | if br_list[-1] == dic[br]: 71 | return True 72 | else: 73 | return False 74 | 75 | 76 | def main(): 77 | ''' 78 | >>> is_balanced('(({[]})}') 79 | False 80 | 81 | >>> is_balanced('..{}') 82 | Traceback (most recent call last): 83 | ... 84 | ValueError: Invalid String. 85 | 86 | >>> is_balanced('([])[]({})') 87 | True 88 | 89 | >>> is_balanced('([)]') 90 | False 91 | 92 | >>> is_balanced_method_2('([])[]({})') 93 | True 94 | ''' 95 | import doctest 96 | doctest.testmod(verbose=True) 97 | 98 | 99 | if __name__ == '__main__': 100 | main() 101 | -------------------------------------------------------------------------------- /Problem 1-30/problem_28.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Palantir. 3 | 4 | Write an algorithm to justify text. Given a sequence of words and an integer 5 | line length k, return a list of strings which represents each line, fully 6 | justified. 7 | 8 | More specifically, you should have as many words as possible in each line. 9 | There should be at least one space between each word. Pad extra spaces when 10 | necessary so that each line has exactly length k. Spaces should be distributed 11 | as equally as possible, with the extra spaces, if any, distributed starting 12 | from the left. 13 | 14 | If you can only fit one word on a line, then you should pad the right-hand side 15 | with spaces. 16 | 17 | Each word is guaranteed not to be longer than k. 18 | 19 | For example, given the list of words 20 | ["the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"] and 21 | k = 16, you should return the following: 22 | 23 | ["the quick brown", # 1 extra space on the left 24 | "fox jumps over", # 2 extra spaces distributed evenly 25 | "the lazy dog"] # 4 extra spaces distributed evenly 26 | ''' 27 | 28 | def justify_words(words, k): 29 | ''' 30 | Justify a list of words 31 | Args: 32 | words(list) 33 | k(int) 34 | Returns: 35 | list 36 | ''' 37 | res = [] 38 | 39 | len_words = num_word = 0 40 | line_words = [] 41 | 42 | for word in words: 43 | if len(word) + len_words + num_word > k: 44 | line = justify_line(line_words, k, len_words, num_word) 45 | res.append(line) 46 | 47 | # re-initialize 48 | len_words = num_word = 0 49 | line_words = [] 50 | 51 | line_words.append(word) 52 | len_words += len(word) 53 | num_word += 1 54 | 55 | if line_words: 56 | line = justify_line(line_words, k, len_words, num_word) 57 | res.append(line) 58 | return res 59 | 60 | 61 | def justify_line(line_words, k, len_words, num_word): 62 | ''' 63 | Args: 64 | line_words(list) 65 | k(int) 66 | len_words(int) 67 | num_word(int) 68 | Returns: 69 | string 70 | ''' 71 | if num_word == 1: 72 | return line_words[0] + ' ' * (k - len(line_words[0])) 73 | 74 | num_space_total = k - len_words 75 | remainder = num_space_total % (num_word - 1) 76 | num_space = num_space_total / (num_word - 1) 77 | 78 | if remainder == 0: # spaces are equally distributed 79 | space = ' ' * num_space 80 | return space.join(line_words) 81 | else: # front half has more space than latter half 82 | space = ' ' * num_space 83 | line_words[remainder] = space.join(line_words[remainder:]) 84 | front_space = ' ' * (num_space + 1) 85 | return front_space.join(line_words[:remainder + 1]) 86 | 87 | 88 | def main(): 89 | ''' 90 | >>> words = ["the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"] 91 | >>> k = 16 92 | >>> justify_words(words, k) 93 | ['the quick brown', 'fox jumps over', 'the lazy dog'] 94 | 95 | >>> words = ['the'] 96 | >>> k = 5 97 | >>> justify_words(words, k) 98 | ['the '] 99 | 100 | >>> words = ["the", "quick", "brown", "fox"] 101 | >>> k = 16 102 | >>> justify_words(words, k) 103 | ['the quick brown', 'fox '] 104 | ''' 105 | 106 | import doctest 107 | doctest.testmod(verbose = True) 108 | 109 | 110 | if __name__ == '__main__': 111 | main() 112 | -------------------------------------------------------------------------------- /Problem 1-30/problem_29.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Amazon. 3 | 4 | Run-length encoding is a fast and simple method of encoding strings. The basic 5 | idea is to represent repeated successive characters as a single count and 6 | character. For example, the string "AAAABBBCCDAA" would be encoded as 7 | "4A3B2C1D2A". 8 | 9 | Implement run-length encoding and decoding. You can assume the string to be 10 | encoded have no digits and consists solely of alphabetic characters. You can 11 | assume the string to be decoded is valid. 12 | ''' 13 | 14 | def encoding(string): 15 | ''' 16 | >>> encoding('AAAABBBCCDAA') 17 | '4A3B2C1D2A' 18 | >>> encoding('') 19 | '' 20 | >>> encoding('AaaB') 21 | '1A2a1B' 22 | ''' 23 | if not string: 24 | return '' 25 | 26 | coding = [] 27 | 28 | code = string[0] 29 | for char in string[1:]: 30 | if char != code[-1]: 31 | coding.append(str(len(code)) + code[-1]) 32 | code = char 33 | else: 34 | code += char 35 | 36 | if code: 37 | coding.append(str(len(code)) + code[-1]) 38 | 39 | return ''.join(coding) 40 | 41 | def decoding(code): 42 | ''' 43 | >>> decoding('4A3B2C1D2A') 44 | 'AAAABBBCCDAA' 45 | >>> decoding('') 46 | '' 47 | >>> decoding('1A2a1B') 48 | 'AaaB' 49 | ''' 50 | if not code: 51 | return '' 52 | 53 | decoding = [] 54 | while code: 55 | to_decode = code[:2] 56 | string = to_decode[1] * int(to_decode[0]) 57 | decoding.append(string) 58 | code = code[2:] if len(code) > 2 else [] 59 | return ''.join(decoding) 60 | 61 | 62 | def others(rle): 63 | ''' 64 | Refer: 65 | https://github.com/r1cc4rdo/daily_coding_problem/blob/master/daily_coding_problem_26_30.py#L97 66 | >>> others('AAAABBBCCDAA') 67 | '4A3B2C1D2A' 68 | >>> others('4A3B2C1D2A') 69 | 'AAAABBBCCDAA' 70 | ''' 71 | if rle.isalpha(): # no numbers, encode 72 | 73 | encoded = '' 74 | while rle: 75 | 76 | idx = 0 77 | while idx < len(rle) and rle[0] == rle[idx]: 78 | idx += 1 79 | 80 | encoded += str(idx) + rle[0] 81 | rle = rle[idx:] 82 | 83 | return encoded 84 | 85 | else: # decode 86 | 87 | return ''.join(c * int(n) for n, c in zip(rle[::2], rle[1::2])) 88 | 89 | 90 | if __name__ == '__main__': 91 | import doctest 92 | doctest.testmod(verbose = True) 93 | -------------------------------------------------------------------------------- /Problem 1-30/problem_30.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Facebook. 3 | 4 | You are given an array of non-negative integers that represents a two-dimensional 5 | elevation map where each element is unit-width wall and the integer is the height. 6 | Suppose it will rain and all spots between two walls get filled up. 7 | 8 | Compute how many units of water remain trapped on the map in O(N) time and O(1) 9 | space. 10 | 11 | For example, given the input [2, 1, 2], we can hold 1 unit of water in the middle. 12 | 13 | Given the input [3, 0, 1, 3, 0, 5], we can hold 3 units in the first index, 2 in 14 | the second, and 3 in the fourth index (we cannot hold 5 since it would run off 15 | to the left), so we can trap 8 units of water. 16 | ''' 17 | ''' 18 | Note: 19 | https://www.geeksforgeeks.org/trapping-rain-water/ 20 | 21 | https://github.com/r1cc4rdo/daily_coding_problem/blob/master/daily_coding_problem_26_30.py#L129 22 | ''' 23 | def water_cnt(arr): 24 | water = 0 25 | 26 | while len(arr) > 2: 27 | # the idea is: from the smallest left/right boundary, accumulate water 28 | # level until reaching a higher wall inside. Then recurse with with the 29 | # new bound, until only two array entries. 30 | lval = arr[0] 31 | rval = arr[-1] 32 | if lval <= rval: 33 | 34 | cnt = 1 35 | while arr[cnt] < arr[0]: 36 | water += arr[0] - arr[cnt] 37 | cnt += 1 38 | 39 | arr = arr[cnt:] 40 | 41 | else: 42 | 43 | cnt = -2 44 | while arr[cnt] < arr[-1]: 45 | water += arr[-1] - arr[cnt] 46 | cnt -= 1 47 | 48 | arr = arr[:cnt + 1] 49 | # print water, arr 50 | return water 51 | 52 | 53 | def main(): 54 | ''' 55 | >>> arr = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1] 56 | >>> water_cnt(arr) 57 | 6 58 | 59 | >>> arr = [3, 0, 1, 3, 0, 5] 60 | >>> water_cnt(arr) 61 | 8 62 | 63 | >>> arr = [2, 1, 2] 64 | >>> water_cnt(arr) 65 | 1 66 | ''' 67 | pass 68 | 69 | if __name__ == '__main__': 70 | import doctest 71 | doctest.testmod(verbose=True) 72 | -------------------------------------------------------------------------------- /Problem 1-30/problem_3_serializer.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Google. 3 | 4 | Given the root to a binary tree, implement serialize(root), which serializes the 5 | tree into a string, and deserialize(s), which deserializes the string back into 6 | the tree. 7 | 8 | For example, given the following Node class 9 | 10 | class Node: 11 | def __init__(self, val, left=None, right=None): 12 | self.val = val 13 | self.left = left 14 | self.right = right 15 | The following test should pass: 16 | 17 | node = Node('root', Node('left', Node('left.left')), Node('right')) 18 | assert deserialize(serialize(node)).left.left.val == 'left.left' 19 | ''' 20 | 21 | class Node(object): 22 | ''' 23 | Args: 24 | val(any) 25 | left(Node) 26 | right(Node) 27 | ''' 28 | def __init__(self, val, left=None, right=None): 29 | self.val = val 30 | self.left = left 31 | self.right = right 32 | 33 | 34 | def serialize(tree_node): 35 | ''' 36 | Use -1 to represent an empty leaf. Use ' ' to sperate different nodes. 37 | 38 | Args: 39 | tree_root(class Node): the root of the tree 40 | 41 | Returns: 42 | string: a serialized tree 43 | ''' 44 | preorder_list = preorder_trav(tree_node) 45 | return ' '.join(str(x) for x in preorder_list) 46 | 47 | 48 | def preorder_trav(node): 49 | ''' 50 | Args: 51 | node(class Node): a node on which the traverse starts 52 | 53 | Returns: 54 | list: pre-order traverse 55 | ''' 56 | tree_list = [] 57 | if node is not None: 58 | tree_list.append(node.val) 59 | tree_list.extend(preorder_trav(node.left)) 60 | tree_list.extend(preorder_trav(node.right)) 61 | 62 | if node is None: 63 | tree_list.append('-1') 64 | return tree_list 65 | 66 | 67 | def deserialize(tree_string): 68 | ''' 69 | Args: 70 | tree_string(string): a serialized tree representation 71 | 72 | Returns: 73 | class Node: the root of a tree 74 | ''' 75 | tree_list = tree_string.split(' ') 76 | tree = rebuild(tree_list) 77 | return tree 78 | 79 | 80 | def rebuild(tree_list): 81 | ''' 82 | Args: 83 | tree_list: a list of all nodes in a tree 84 | 85 | Returns: 86 | class Node: the root of a tree 87 | ''' 88 | if len(tree_list) != 0: # use == to compare value, 'is' to compare objects 89 | value = tree_list.pop(0) 90 | if value != '-1': # use == or != to compare two strings 91 | node = Node(value) 92 | node.left = rebuild(tree_list) 93 | node.right = rebuild(tree_list) 94 | else: 95 | node = Node(None) 96 | return node 97 | 98 | 99 | def main(): 100 | ''' 101 | unit test 102 | ''' 103 | node = Node('root', Node('left', Node('left.left')), Node('right')) 104 | # node = Node('root') 105 | print serialize(node) 106 | print deserialize(serialize(node)).val 107 | print deserialize(serialize(node)).left.val 108 | print deserialize(serialize(node)).left.left.val 109 | print deserialize(serialize(node)).right.val 110 | 111 | 112 | if __name__ == '__main__': 113 | main() 114 | -------------------------------------------------------------------------------- /Problem 1-30/problem_4.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Stripe. 3 | 4 | Given an array of integers, find the first missing positive integer in linear 5 | time and constant space. In other words, find the lowest positive integer that 6 | does not exist in the array. The array can contain duplicates and negative 7 | numbers as well. 8 | 9 | For example, the input [3, 4, -1, 1] should give 2. The input [1, 2, 0] should 10 | give 3. 11 | 12 | You can modify the input array in-place. 13 | 14 | ----------- 15 | 16 | Some other thoughts: 17 | 18 | A naive method to solve this problem is to search all positive integers, starting 19 | from 1 in the given array. We may have to search at most n+1 numbers in the given 20 | array. So this solution takes O(n^2) in worst case. 21 | 22 | We can use sorting to solve it in lesser time complexity. We can sort the array 23 | in O(nLogn) time. Once the array is sorted, then all we need to do is a linear 24 | scan of the array. So this approach takes O(nLogn + n) time which is O(nLogn). 25 | 26 | We can also use hashing. We can build a hash table of all positive elements in 27 | the given array. Once the hash table is built. We can look in the hash table for 28 | all positive integers, starting from 1. As soon as we find a number which is not 29 | there in hash table, we return it. This approach may take O(n) time on average, 30 | but it requires O(n) extra space. 31 | ''' 32 | 33 | def solution(alist): 34 | ''' 35 | Use the index of the list to denote whether we have seen this number. 36 | For example: 37 | We see 2, then change the number on index 2 from + to -. 38 | [2, 4, 1] --> [2, 4, -1] 39 | 40 | ------ 41 | Args: 42 | alist(list): a list of numbers may includes duplicates and negative 43 | Returns: 44 | int: the smallest positive integer missing in the given list 45 | ''' 46 | pos_list = remove_negative(alist) 47 | modify_index(pos_list) 48 | smallest_pos = find_smallest_pos(pos_list) 49 | return smallest_pos 50 | 51 | 52 | def remove_negative(alist): 53 | ''' 54 | Args: 55 | alist(list): a list of numbers may includes duplicates and negative 56 | Returns: 57 | list: a list of numbers may includes only duplicates, no negative and 0 58 | ''' 59 | 60 | ''' 61 | Note: 62 | When reading, 'alist' is a reference to the original 'list', and 'list[:]' 63 | shallow-copies the list. 64 | 65 | When assigning, 'alist' (re)binds the name and 'alist[:]' slice-assigns, 66 | replacing what was previously in the list. 67 | ''' 68 | # filter seems not an in-place modification 69 | # new_list = list(filter(lambda x: x > 0, alist)) 70 | 71 | # following is not an in-place way either 72 | # alist = [x for x in alist if x > 0] 73 | 74 | # finally, this seems like an in-place operate as the id(alist) remains same 75 | # correct me if I'm wrong 76 | alist[:] = [x for x in alist if x > 0] 77 | return alist 78 | 79 | 80 | def modify_index(pos_list): 81 | ''' 82 | Args: 83 | pos_list(list) 84 | Returns: 85 | list 86 | ''' 87 | for num in pos_list: 88 | if abs(num) - 1 < len(pos_list) and pos_list[abs(num) - 1] > 0: 89 | pos_list[abs(num) - 1] = - pos_list[abs(num) - 1] 90 | 91 | 92 | def find_smallest_pos(pos_list): 93 | # return pos_list 94 | ''' 95 | Args: 96 | pos_list(list) 97 | Returns: 98 | int 99 | ''' 100 | for idx, num in enumerate(pos_list): 101 | if num > 0: 102 | return idx + 1 103 | return len(pos_list) + 1 104 | 105 | 106 | def main(): 107 | # test_list = [3, 4, -1, 1] 108 | # test_list = [1, 2, 0] 109 | test_list = [2, 4, -8, 10, 15, 0, 0 , -1, 1] 110 | # test_list = [0, 0, 0] 111 | print solution(test_list) 112 | 113 | 114 | if __name__ == '__main__': 115 | main() 116 | -------------------------------------------------------------------------------- /Problem 1-30/problem_5.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Jane Street. 3 | 4 | cons(a, b) constructs a pair, and car(pair) and cdr(pair) returns the first and 5 | last element of that pair. For example, car(cons(3, 4)) returns 3, and 6 | cdr(cons(3, 4)) returns 4. 7 | 8 | Given this implementation of cons: 9 | 10 | def cons(a, b): 11 | def pair(f): 12 | return f(a, b) 13 | return pair 14 | Implement car and cdr. 15 | ''' 16 | 17 | def cons(a, b): 18 | ''' 19 | Args: 20 | a(int) 21 | b(int) 22 | Returns: 23 | function: a function has another function 'f' as argument 24 | ''' 25 | def pair(f): 26 | ''' 27 | Args: 28 | f(function) 29 | Returns: 30 | function: that has a, b as two arguments 31 | ''' 32 | return f(a, b) 33 | return pair 34 | 35 | 36 | def car(func): 37 | ''' 38 | Args: 39 | func(function) 40 | Returns: 41 | function: define the function 'f' 42 | ''' 43 | # method 1 44 | return func(lambda x, y: x) 45 | 46 | # method 2 47 | # ------------ 48 | # def f(a, b): 49 | # return a 50 | # return func(f) 51 | 52 | 53 | def cdr(func): 54 | ''' 55 | Args: 56 | func(function) 57 | Returns: 58 | function: define the function 'f' 59 | ''' 60 | return func(lambda x, y: y) 61 | 62 | 63 | def main(): 64 | print car(cons(3, 4)) 65 | print cdr(cons(3, 4)) 66 | 67 | 68 | if __name__ == '__main__': 69 | main() 70 | -------------------------------------------------------------------------------- /Problem 1-30/problem_6.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Google. 3 | 4 | An XOR linked list is a more memory efficient doubly linked list. Instead of each 5 | node holding next and prev fields, it holds a field named both, which is a XOR of 6 | the next node and the previous node. Implement a XOR linked list; it has an 7 | add(element) which adds the element to the end, and a get(index) which returns 8 | the node at index. 9 | 10 | If using a language that has no pointers (such as Python), you can assume you 11 | have access to 'get_pointer' and 'dereference_pointer' functions that converts 12 | between nodes and memory addresses. 13 | 14 | ---------- 15 | XOR 16 | 0 0 0 17 | 0 1 1 18 | 1 0 1 19 | 1 1 1 20 | ---------- 21 | 22 | XOR Linked List: 23 | None -> Node(A) -> Node(B) -> ... -> Node(X) -> None 24 | 25 | num_A = 0 XOR address(B) 26 | num_B = address(A) XOR address(C) 27 | ... 28 | num_X = address(W) XOR address(Y) 29 | ''' 30 | 31 | ''' 32 | I think this problem will only show up for C and C++. 33 | There is no way to do it in python or JAVA. 34 | ''' 35 | 36 | class Node(object): 37 | def __init__(self, val = None, both = None): 38 | self.val = val 39 | self.both = None 40 | 41 | class XOR_List(object): 42 | def __init__(self, Node = None): 43 | self.head = Node(0, 0) 44 | self.tail = Node(0, 0) 45 | self.length = 0 46 | 47 | def add(self, element): 48 | if length == 0: 49 | self.head.both = 0 ^ get_pointer(element) 50 | self.tail.both = get_pointer(element) ^ 0 51 | element.both = get_pointer(self.head) ^ get_pointer(self.tail) 52 | else: 53 | prev = dereference_pointer(self.tail.both) 54 | prev_prev_addr = prev.both ^ get_pointer(self.tail) 55 | prev.both = prev_prev_addr ^ get_pointer(element) 56 | element.both = get_pointer(prev) ^ get_pointer(self.tail.both) 57 | self.tail.both = get_pointer(element) ^ 0 58 | length += 1 59 | 60 | def get(self, index): 61 | if index >= length: 62 | raise ValueError('Invalid Index!') 63 | else: 64 | ptr = self.head.both 65 | prev_addr = get_pointer(self.head) 66 | 67 | while index > 0: 68 | node = dereference_pointer(ptr) 69 | ptr = node.both ^ prev_addr 70 | prev_addr = ptr 71 | index -= 1 72 | 73 | if index == 0: 74 | return dereference_pointer(ptr) 75 | 76 | 77 | def main(): 78 | pass 79 | 80 | 81 | if __name__ == '__main__': 82 | main() 83 | -------------------------------------------------------------------------------- /Problem 1-30/problem_7.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Facebook. 3 | 4 | Given the mapping a = 1, b = 2, ... z = 26, and an encoded message, count the 5 | number of ways it can be decoded. 6 | 7 | For example, the message '111' would give 3, since it could be decoded as 'aaa', 8 | 'ka', and 'ak'. 9 | 10 | You can assume that the messages are decodable. For example, '001' is not allowed. 11 | 12 | ''' 13 | ''' 14 | Not sure if '10001' is valid; 15 | 16 | Question: How do deal with 0 if there are any? 17 | Let's just assume there is no ZERO in the message; 18 | ''' 19 | 20 | 21 | def solution(message): 22 | ''' 23 | To decode message. 24 | Args: 25 | message(string) 26 | Returns: 27 | int 28 | ''' 29 | # return decode_cnt(list(message)) 30 | return decode_cnt_no_zero(list(message)) 31 | 32 | 33 | def decode_cnt_no_zero(msg_list): 34 | ''' 35 | Args: 36 | msg_list(list) 37 | Returns: 38 | int 39 | ''' 40 | if len(msg_list) <= 1: 41 | return 1 42 | 43 | if len(msg_list) >= 2: 44 | if 1 <= int(''.join(msg_list[0:2])) <= 26: 45 | return (decode_cnt_no_zero(msg_list[1:]) + 46 | decode_cnt_no_zero(msg_list[2:])) 47 | return decode_cnt_no_zero(msg_list[1:]) 48 | 49 | """ 50 | def decode_cnt(msg_list): 51 | ''' 52 | A solution trying to solve when there are zeros. 53 | Args: 54 | msg_list(list): the list of message waiting for decoding 55 | Returns: 56 | int: count of how many ways to decode 57 | ''' 58 | if len(msg_list) == 1: 59 | return 1 if int(msg_list[0]) != 0 else 0 60 | 61 | if len(msg_list) == 2: 62 | count = 0 63 | if int(msg_list[0]) != 0 and int(msg_list[1]) != 0: 64 | count += 1 65 | if 1 <= int(''.join(msg_list)) <= 26: 66 | count += 1 67 | return count 68 | 69 | if len(msg_list) > 2: 70 | count = 0 71 | if int(msg_list[0]) != 0: 72 | count += decode_cnt(msg_list[1:]) 73 | if 1 <= int(''.join(msg_list[0:2])) <= 26: 74 | count += decode_cnt(msg_list[2:]) 75 | return count 76 | """ 77 | 78 | def main(): 79 | msg = '1119' 80 | print solution(msg) 81 | 82 | if __name__ == '__main__': 83 | main() 84 | -------------------------------------------------------------------------------- /Problem 1-30/problem_8.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Google. 3 | 4 | A unival tree (which stands for "universal value") is a tree where all nodes 5 | under it have the same value. 6 | 7 | Given the root to a binary tree, count the number of unival subtrees. 8 | 9 | For example, the following tree has 5 unival subtrees: 10 | 11 | 0 12 | / \ 13 | 1 0 14 | / \ 15 | 1 0 16 | / \ 17 | 1 1 18 | ''' 19 | class Node(object): 20 | ''' 21 | Tree Node 22 | If the tree rooted at this node is a unival tree, then 'is_unival' == True 23 | ''' 24 | def __init__(self, val=None, left=None, right=None, is_unival=False): 25 | self.val = val 26 | self.left = left 27 | self.right = right 28 | self.is_unival = is_unival 29 | 30 | 31 | def count_unival_subtree(node): 32 | ''' 33 | Args: 34 | node(Node): The root node of a sub-tree 35 | 36 | Returns: 37 | int 38 | ''' 39 | if node.left == node.right == None: 40 | node.is_unival = True 41 | return 1 42 | 43 | left = 0 44 | right = 0 45 | if node.left != None: 46 | left = count_unival_subtree(node.left) 47 | if node.right != None: 48 | right = count_unival_subtree(node.right) 49 | 50 | if node.left and node.right: # node has both left and right 51 | if (node.left.is_unival and node.right.is_unival 52 | and node.val == node.left.val == node.right.val): 53 | node.is_unival = True 54 | return left + right + 1 55 | else: 56 | return left + right 57 | else: # either left or right is missing 58 | if ((not node.left and node.val == node.right.val and node.right.is_unival) 59 | or (not node.right and node.val == node.left.val and node.left.is_unival)): 60 | node.is_unival = True 61 | return left + right + 1 62 | else: 63 | return left + right 64 | 65 | 66 | def main(): 67 | root = Node('0', Node('1'), Node('0', Node('1', Node('1'), Node('1')), Node('0'))) 68 | print count_unival_subtree(root) 69 | 70 | 71 | if __name__ == '__main__': 72 | main() 73 | -------------------------------------------------------------------------------- /Problem 1-30/problem_9.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Airbnb. 3 | 4 | Given a list of integers, write a function that returns the largest sum of 5 | non-adjacent numbers. Numbers can be 0 or negative. 6 | 7 | For example, [2, 4, 6, 2, 5] should return 13, since we pick 2, 6, and 5. 8 | [5, 1, 1, 5] should return 10, since we pick 5 and 5. 9 | 10 | Follow-up: Can you do this in O(N) time and constant space? 11 | ''' 12 | 13 | def find_max_sum(int_list): 14 | ''' 15 | Use Dynamic Programming to find the max sum of non-adjacent numbers. 16 | Args: 17 | int_list(list): a list of integers that may have 0 or negative 18 | Returns: 19 | int 20 | ''' 21 | if not int_list: 22 | return 0 23 | elif len(int_list) <= 2: 24 | return max(int_list) 25 | 26 | last_num = int_list[-1] # last number in the list 27 | with_last = find_max_sum(int_list[:-2]) + last_num # sum include last_num 28 | without_last = find_max_sum(int_list[:-1]) # sum without last_num 29 | return max(with_last, without_last) 30 | 31 | 32 | def main(): 33 | # test_list = [2, 4, 6, 2, 5] 34 | # test_list = [5, 1, 1, 5] 35 | test_list = [-8, 4, -3, 2, 3, 4] 36 | print find_max_sum(test_list) 37 | 38 | 39 | if __name__ == '__main__': 40 | main() 41 | -------------------------------------------------------------------------------- /Problem 31-60/problem_31.py: -------------------------------------------------------------------------------- 1 | # -- coding: utf-8 -- 2 | ''' 3 | This problem was asked by Google. 4 | 5 | The edit distance between two strings refers to the minimum number of character 6 | insertions, deletions, and substitutions required to change one string to the 7 | other. For example, the edit distance between “kitten” and “sitting” is three: 8 | substitute the 'k' for 's', substitute the 'e' for 'i', and append a 'g'. 9 | 10 | Given two strings, compute the edit distance between them. 11 | ''' 12 | def edit_distance(str1, str2): 13 | ''' 14 | Dynamic Programming 15 | Args: 16 | str1(string) 17 | str2(string) 18 | Returns: 19 | int 20 | ''' 21 | m, n = len(str1), len(str2) 22 | 23 | dp = [[0] * (n+1) for i in xrange(m+1)] 24 | 25 | for i in xrange(n+1): 26 | dp[0][i] = i 27 | 28 | for j in xrange(m+1): 29 | dp[j][0] = j 30 | 31 | for i in xrange(1, m+1): 32 | for j in xrange(1, n+1): 33 | if str1[i-1] == str2[j-1]: 34 | dp[i][j] = dp[i-1][j-1] 35 | else: 36 | dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1 37 | 38 | return dp[m][n] 39 | 40 | 41 | def main(): 42 | ''' 43 | >>> edit_distance('kitten', 'sitting') 44 | 3 45 | >>> edit_distance('', '') 46 | 0 47 | >>> edit_distance('', 'hi') 48 | 2 49 | ''' 50 | import doctest 51 | doctest.testmod(verbose=True) 52 | 53 | if __name__ == '__main__': 54 | main() 55 | -------------------------------------------------------------------------------- /Problem 31-60/problem_32.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Jane Street. 3 | 4 | Suppose you are given a table of currency exchange rates, represented as a 2D 5 | array. Determine whether there is a possible arbitrage: that is, whether there 6 | is some sequence of trades you can make, starting with some amount A of any 7 | currency, so that you can end up with some amount greater than A of that 8 | currency. 9 | 10 | There are no transaction costs and you can trade fractional quantities. 11 | ''' 12 | ''' 13 | Note: 14 | https://www.dailycodingproblem.com/blog/how-to-find-arbitrage-opportunities-in-python/ 15 | 16 | We can model the currencies and the exchange rates as a graph, where the nodes 17 | are the currencies and the edges are the exchange rates between each currency. 18 | Since our table is complete, the graph is also complete. Then, to solve this 19 | problem, we need to find a cycle whose edge weights product is greater than 1. 20 | 21 | This seems hard to do faster than brute force, so let’s try to reduce it down to 22 | a problem we already know we can solve faster than brute force. (Scroll down if 23 | you want to see exactly how slow brute force is!) 24 | 25 | Here’s a hint: log(a * b) = log(a) + log(b). 26 | 27 | If we take the negative log of the edge weights, the problem of finding a 28 | cumulative product that’s greater than 1 turns into the problem of finding a 29 | negative sum cycle! 30 | 31 | For example, say we have a weighted edge path a -> b -> c -> d. Since we want to 32 | see if a * b * c * d > 1, we’ll take the negative log of each edge: 33 | 34 | -log(a) -> -log(b) -> -log(c) -> -log(d). 35 | 36 | The total cost of this path will then be 37 | 38 | -(log(a) + log(b) + log(c) + log(d)) = -log(a * b * c * d). 39 | 40 | -log(x) < 0 if x is greater than 1, so that’s why if we have a negative cost 41 | cycle, if means that the product of the weighted edges is bigger than 1. 42 | 43 | The Bellman-Ford algorithm can detect negative cycles. So if we run Bellman-Ford 44 | on our graph and discover one, then that means its corresponding edge weights 45 | multiply out to more than 1, and thus we can perform an arbitrage. 46 | 47 | As a refresher, the Bellman-Ford algorithm is commonly used to find the shortest 48 | path between a source vertex and each of the other vertices. If the graph contains 49 | a negative cycle, however, it can detect it and throw an exception (or, in our 50 | case, return true). The main idea of Bellman-Ford is this: 51 | 52 | Since the longest path in any graph has at most |V| - 1 edges, if we take all 53 | the direct edges from our source node, then we have all the one-edged shortest 54 | paths; once we take edges from there, we have all the two-edged shortest paths; 55 | all the way until |V| - 1 sized paths. 56 | 57 | If, after |V| - 1 iterations of this, we can still find a smaller path, then 58 | there must be a negative cycle in the graph. We can start our algorithm on any 59 | vertex in our graph – since our graph is connected (by virtue of it being complete), 60 | then if there’s a negative cycle in our graph, we’ll find it. 61 | ''' 62 | from math import log 63 | 64 | def arbitrage(table): 65 | transformed_graph = [[-log(edge) for edge in row] for row in graph] 66 | 67 | # Pick any source vertex -- we can run Bellman-Ford from any vertex and 68 | # get the right result 69 | source = 0 70 | n = len(transformed_graph) 71 | min_dist = [float('inf')] * n 72 | 73 | min_dist[source] = 0 74 | 75 | # Relax edges |V - 1| times 76 | for i in range(n - 1): 77 | for v in range(n): 78 | for w in range(n): 79 | if min_dist[w] > min_dist[v] + transformed_graph[v][w]: 80 | min_dist[w] = min_dist[v] + transformed_graph[v][w] 81 | 82 | # If we can still relax edges, then we have a negative cycle 83 | for v in range(n): 84 | for w in range(n): 85 | if min_dist[w] > min_dist[v] + transformed_graph[v][w]: 86 | return True 87 | 88 | return False 89 | 90 | ''' 91 | Because of the triply-nested for loop, this runs in O(N^3) time, and because 92 | we’re creating a transformed copy of the old graph we’re using O(N^2) space. 93 | 94 | P.S: How slow is brute force? Well, we would have to check every single path in 95 | the graph that starts and ends at the same node, and our graph is complete. For 96 | each node, since our graph is connected, we can have every single permutation of 97 | any number of vertices up to N - 1, so brute force would be on the order of 98 | O(N!) time! 99 | ''' 100 | -------------------------------------------------------------------------------- /Problem 31-60/problem_33.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Microsoft. 3 | 4 | Compute the running median of a sequence of numbers. That is, given a stream of 5 | numbers, print out the median of the list so far on each new element. 6 | 7 | Recall that the median of an even-numbered list is the average of the two middle 8 | numbers. 9 | 10 | For example, given the sequence [2, 1, 5, 7, 2, 0, 5], your algorithm should 11 | print out: 12 | 13 | 2 14 | 1.5 15 | 2 16 | 3.5 17 | 2 18 | 2 19 | 2 20 | ''' 21 | from __future__ import division 22 | import heapq 23 | import random 24 | 25 | def median(total_list=None): 26 | ''' 27 | Find median of either a stream or a list 28 | Args: 29 | (total_list(list)) 30 | Returns: 31 | None 32 | ''' 33 | max_heap = [] 34 | min_heap = [] 35 | if total_list is None: # pass a stream of random integer 36 | for num in random_int(): 37 | print 'random int = ' + str(num) 38 | max_heap, min_heap = insert_num(max_heap, min_heap, num) 39 | print_median(max_heap, min_heap) 40 | 41 | else: # pass a list 42 | if not total_list: 43 | print_median(max_heap, min_heap) 44 | return 45 | 46 | for i in xrange(0, len(total_list)): 47 | max_heap, min_heap = insert_num(max_heap, min_heap, total_list[i]) 48 | print_median(max_heap, min_heap) 49 | 50 | 51 | def insert_num(max_heap, min_heap, num): 52 | if len(max_heap) == len(min_heap) == 0: 53 | heapq.heappush(max_heap, -num) 54 | elif num < -max_heap[0]: 55 | heapq.heappush(max_heap, -num) 56 | else: 57 | heapq.heappush(min_heap, num) 58 | 59 | return balance_heap(max_heap, min_heap) 60 | 61 | 62 | def balance_heap(max_heap, min_heap): 63 | while abs(len(max_heap) - len(min_heap)) > 1: 64 | if len(max_heap) > len(min_heap): 65 | real_value = -heapq.heappop(max_heap) 66 | heapq.heappush(min_heap, real_value) 67 | else: 68 | value = heapq.heappop(min_heap) 69 | heapq.heappush(max_heap, -value) 70 | 71 | return max_heap, min_heap 72 | 73 | 74 | def print_median(max_heap, min_heap): 75 | print 'max_heap = ' + str(max_heap) 76 | print 'min_heap = ' + str(min_heap) 77 | 78 | if not max_heap and not min_heap: 79 | print 0 80 | return 81 | 82 | if len(max_heap) == len(min_heap): 83 | num = (-max_heap[0] + min_heap[0]) / 2 84 | print int(num) if int(num) == float(num) else num 85 | elif len(max_heap) > len(min_heap): 86 | print -max_heap[0] 87 | else: 88 | print min_heap[0] 89 | 90 | 91 | def random_int(): 92 | for i in xrange(10): 93 | yield random.randint(0, 10) 94 | 95 | 96 | def main(): 97 | # median([]) 98 | # median([2, 1, 5, 7, 2, 0, 5]) 99 | median() 100 | # median([-1, -2, 3]) 101 | 102 | 103 | if __name__ == '__main__': 104 | main() 105 | -------------------------------------------------------------------------------- /Problem 31-60/problem_34.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Quora. 3 | 4 | Given a string, find the palindrome that can be made by inserting the fewest 5 | number of characters as possible anywhere in the word. If there is more than 6 | one palindrome of minimum length that can be made, return the lexicographically 7 | earliest one (the first one alphabetically). 8 | 9 | For example, given the string "race", you should return "ecarace", since we can 10 | add three letters to it (which is the smallest amount to make a palindrome). 11 | There are seven other palindromes that can be made from "race" by adding three 12 | letters, but "ecarace" comes first alphabetically. 13 | 14 | As another example, given the string "google", you should return "elgoogle". 15 | ''' 16 | ''' 17 | Reference: 18 | https://www.geeksforgeeks.org/dynamic-programming-set-28-minimum-insertions-to-form-a-palindrome/ 19 | 20 | Recursive Solution: 21 | 22 | The minimum number of insertions in the string str[l…..h] can be given as: 23 | minInsertions(str[l+1…..h-1]) if str[l] is equal to str[h] 24 | min(minInsertions(str[l…..h-1]), minInsertions(str[l+1…..h])) + 1 otherwise 25 | 26 | Dynamic Programming: 27 | If we observe the above approach carefully, we can find that it exhibits 28 | overlapping subproblems. 29 | Suppose we want to find the minimum number of insertions in string “abcde”: 30 | 31 | abcde 32 | / | \ 33 | / | \ 34 | bcde abcd bcd <- case 3 is discarded as str[l] != str[h] 35 | / | \ / | \ 36 | / | \ / | \ 37 | cde bcd cd bcd abc bc 38 | / | \ / | \ /|\ / | \ 39 | de cd d cd bc c…………………. 40 | The substrings (bcd) show that the recursion to be terminated and the recursion 41 | tree cannot originate from there. Substring in the same color indicates 42 | overlapping subproblems. 43 | 44 | 45 | 46 | How to reuse solutions of subproblems? 47 | We can create a table to store results of subproblems so that they can be used 48 | directly if same subproblem is encountered again. 49 | 50 | The below table represents the stored values for the string abcde. 51 | 52 | a b c d e 53 | ---------- 54 | 0 1 2 3 4 55 | 0 0 1 2 3 56 | 0 0 0 1 2 57 | 0 0 0 0 1 58 | 0 0 0 0 0 59 | How to fill the table? 60 | The table should be filled in diagonal fashion. For the string abcde, 0….4, the 61 | following should be order in which the table is filled: 62 | 63 | Gap = 1: 64 | (0, 1) (1, 2) (2, 3) (3, 4) 65 | 66 | Gap = 2: 67 | (0, 2) (1, 3) (2, 4) 68 | 69 | Gap = 3: 70 | (0, 3) (1, 4) 71 | 72 | Gap = 4: 73 | (0, 4) 74 | ''' 75 | -------------------------------------------------------------------------------- /Problem 31-60/problem_35.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Google. 3 | 4 | Given an array of strictly the characters 'R', 'G', and 'B', segregate the values 5 | of the array so that all the Rs come first, the Gs come second, and the Bs come 6 | last. You can only swap elements of the array. 7 | 8 | Do this in linear time and in-place. 9 | 10 | For example, given the array ['G', 'B', 'R', 'R', 'B', 'R', 'G'], it should 11 | become ['R', 'R', 'R', 'G', 'G', 'B', 'B']. 12 | ''' 13 | ''' 14 | Note: 15 | This solution should take advantage of the expected high number of equal value 16 | elements. 17 | 18 | The following solution does at most two passes, and therefore is O(n). 19 | 20 | https://github.com/r1cc4rdo/daily_coding_problem/blob/master/daily_coding_problem_31_35.py#L84 21 | ''' 22 | def sort(rgbs): 23 | left_index, right_index = 0, len(rgbs) - 1 24 | while True: # move Rs to front 25 | 26 | while rgbs[left_index] == 'R' and left_index < right_index: # advance to first non R 27 | left_index += 1 28 | 29 | while rgbs[right_index] != 'R' and left_index < right_index: # regress to last R 30 | right_index -= 1 31 | 32 | if left_index >= right_index: 33 | break 34 | 35 | rgbs[left_index], rgbs[right_index] = rgbs[right_index], rgbs[left_index] 36 | 37 | right_index = len(rgbs) - 1 38 | while True: # move Bs to tail 39 | 40 | while rgbs[left_index] != 'B' and left_index < right_index: # advance to first B 41 | left_index += 1 42 | 43 | while rgbs[right_index] == 'B' and left_index < right_index: # regress to last non B 44 | right_index -= 1 45 | 46 | if left_index >= right_index: 47 | break 48 | 49 | rgbs[left_index], rgbs[right_index] = rgbs[right_index], rgbs[left_index] 50 | 51 | return rgbs 52 | 53 | 54 | def main(): 55 | print sort(['G', 'B', 'R', 'R', 'B', 'R', 'G']) 56 | 57 | 58 | if __name__ == '__main__': 59 | main() 60 | -------------------------------------------------------------------------------- /Problem 31-60/problem_36.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This problem was asked by Dropbox. 3 | 4 | Given the root to a binary search tree, find the second largest node in the tree. 5 | ''' 6 | ''' 7 | Note: 8 | https://www.geeksforgeeks.org/second-largest-element-in-binary-search-tree-bst/ 9 | 10 | The second largest element is second last element in inorder traversal and second 11 | element in reverse inorder traversal. We traverse given Binary Search Tree in 12 | reverse inorder and keep track of counts of nodes visited. Once the count becomes 13 | 2, we print the node. 14 | ''' 15 | -------------------------------------------------------------------------------- /Problem Descriptions.md: -------------------------------------------------------------------------------- 1 | # Problem Description 2 | 3 | ----- 4 | ## Table of Content 5 | 6 | [Problem 1-30](#1-30) 7 | [Problem 31-60](#31-60) 8 | 9 | ## Problem 31-60 10 | 11 | --- 12 | ### Problem 36 13 | This problem was asked by Dropbox. 14 | 15 | Given the root to a binary search tree, find the second largest node in the tree. 16 | 17 | ### Problem 35 18 | This problem was asked by Google. 19 | 20 | Given an array of strictly the characters `'R'`, `'G'`, and `'B'`, segregate the values of the array so that all the Rs come first, the Gs come second, and the Bs come last. You can only swap elements of the array. 21 | 22 | Do this in linear time and in-place. 23 | 24 | For example, given the array `['G', 'B', 'R', 'R', 'B', 'R', 'G']`, it should become `['R', 'R', 'R', 'G', 'G', 'B', 'B']`. 25 | 26 | 27 | ### Problem 34 28 | This problem was asked by Quora. 29 | 30 | Given a string, find the palindrome that can be made by inserting the fewest number of characters as possible anywhere in the word. If there is more than one palindrome of minimum length that can be made, return the lexicographically earliest one (the first one alphabetically). 31 | 32 | For example, given the string `"race"`, you should return `"ecarace"`, since we can add three letters to it (which is the smallest amount to make a palindrome). There are seven other palindromes that can be made from `"race"` by adding three letters, but `"ecarace"` comes first alphabetically. 33 | 34 | As another example, given the string `"google"`, you should return `"elgoogle"`. 35 | 36 | ### Problem 33 37 | This problem was asked by Microsoft. 38 | 39 | Compute the running median of a sequence of numbers. That is, given a stream of numbers, print out the median of the list so far on each new element. 40 | 41 | Recall that the median of an even-numbered list is the average of the two middle numbers. 42 | 43 | For example, given the sequence `[2, 1, 5, 7, 2, 0, 5]`, your algorithm should print out: 44 | ``` 45 | 2 46 | 1.5 47 | 2 48 | 3.5 49 | 2 50 | 2 51 | 2 52 | ``` 53 | 54 | ### Problem 32 55 | This problem was asked by Jane Street. 56 | 57 | Suppose you are given a table of currency exchange rates, represented as a 2D array. Determine whether there is a possible arbitrage: that is, whether there is some sequence of trades you can make, starting with some amount A of any currency, so that you can end up with some amount greater than A of that currency. 58 | 59 | There are no transaction costs and you can trade fractional quantities. 60 | 61 | ### Problem 31 62 | This problem was asked by Google. 63 | 64 | The edit distance between two strings refers to the minimum number of character insertions, deletions, and substitutions required to change one string to the other. For example, the edit distance between `“kitten”` and `“sitting”` is three: substitute the `“k”` for `“s”`, substitute the `“e”` for `“i”`, and append a `“g”`. 65 | 66 | Given two strings, compute the edit distance between them. 67 | 68 | ---- 69 | 70 | ## Problem 1-30 71 | 72 | ---- 73 | ### Problem 30 74 | This problem was asked by Facebook. 75 | 76 | You are given an array of non-negative integers that represents a two-dimensional elevation map where each element is unit-width wall and the integer is the height. Suppose it will rain and all spots between two walls get filled up. 77 | 78 | Compute how many units of water remain trapped on the map in `O(N)` time and `O(1)` space. 79 | 80 | For example, given the input `[2, 1, 2]`, we can hold 1 unit of water in the middle. 81 | 82 | Given the input `[3, 0, 1, 3, 0, 5]`, we can hold 3 units in the first index, 2 in the second, and 3 in the fourth index (we cannot hold 5 since it would run off to the left), so we can trap 8 units of water. 83 | 84 | ### Problem 29 85 | This problem was asked by Amazon. 86 | 87 | Run-length encoding is a fast and simple method of encoding strings. The basic idea is to represent repeated successive characters as a single count and character. For example, the string `"AAAABBBCCDAA"` would be encoded as `"4A3B2C1D2A"`. 88 | 89 | Implement run-length encoding and decoding. You can assume the string to be encoded have no digits and consists solely of alphabetic characters. You can assume the string to be decoded is valid. 90 | 91 | ### Problem 28 92 | This problem was asked by Palantir. 93 | 94 | Write an algorithm to justify text. Given a sequence of words and an integer line length `k`, return a list of strings which represents each line, fully justified. 95 | 96 | More specifically, you should have as many words as possible in each line. There should be at least one space between each word. Pad extra spaces when necessary so that each line has exactly length `k`. Spaces should be distributed as equally as possible, with the extra spaces, if any, distributed starting from the left. 97 | 98 | If you can only fit one word on a line, then you should pad the right-hand side with spaces. 99 | 100 | Each word is guaranteed not to be longer than `k`. 101 | 102 | For example, given the list of words `["the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"]` and `k = 16`, you should return the following: 103 | 104 | ``` 105 | ["the quick brown", # 1 extra space on the left 106 | "fox jumps over", # 2 extra spaces distributed evenly 107 | "the lazy dog"] # 4 extra spaces distributed evenly 108 | ``` 109 | 110 | 111 | ### Problem 27 112 | This problem was asked by Facebook. 113 | 114 | Given a string of round, curly, and square open and closing brackets, return whether the brackets are balanced (well-formed). 115 | 116 | For example, given the string `"([])[]({})"`, you should return `true`. 117 | 118 | Given the string `"([)]"` or `"((()"`, you should return false. 119 | 120 | 121 | ### Problem 26 122 | This problem was asked by Google. 123 | 124 | Given a singly linked list and an integer `k`, remove the kth last element from the list. `k` is guaranteed to be smaller than the length of the list. 125 | 126 | The list is very long, so making more than one pass is prohibitively expensive. 127 | 128 | Do this in constant space and in one pass. 129 | 130 | ### Problem 25 131 | This problem was asked by Facebook. 132 | 133 | Implement regular expression matching with the following special characters: 134 | 135 | `. (period)` which matches any single character 136 | `* (asterisk)` which matches zero or more of the preceding element 137 | That is, implement a function that takes in a string and a valid regular expression and returns whether or not the string matches the regular expression. 138 | 139 | For example, given the regular expression `"ra."` and the string `"ray"`, your function should return true. The same regular expression on the string `"raymond"` should return false. 140 | 141 | Given the regular expression `".*at"` and the string `"chat"`, your function should return true. The same regular expression on the string "chats" should return false. 142 | 143 | ### Problem 24 144 | This problem was asked by Google. 145 | 146 | Implement locking in a binary tree. A binary tree node can be locked or unlocked only if all of its descendants or ancestors are not locked. 147 | 148 | Design a binary tree node class with the following methods: 149 | 150 | `is_locked`, which returns whether the node is locked 151 | `lock`, which attempts to lock the node. If it cannot be locked, then it should return false. Otherwise, it should lock it and return true. 152 | `unlock`, which unlocks the node. If it cannot be unlocked, then it should return false. Otherwise, it should unlock it and return true. 153 | 154 | You may augment the node to add parent pointers or any other property you would like. You may assume the class is used in a single-threaded program, so there is no need for actual locks or mutexes. Each method should run in `O(h)`, where `h` is the height of the tree. 155 | 156 | ### Problem 23 157 | This problem was asked by Google. 158 | 159 | You are given an M by N matrix consisting of booleans that represents a board. Each True boolean represents a wall. Each False boolean represents a tile you can walk on. 160 | 161 | Given this matrix, a start coordinate, and an end coordinate, return the minimum number of steps required to reach the end coordinate from the start. If there is no possible path, then return null. You can move up, left, down, and right. You cannot move through walls. You cannot wrap around the edges of the board. 162 | 163 | For example, given the following board: 164 | 165 | ``` 166 | [[f, f, f, f], 167 | [t, t, f, t], 168 | [f, f, f, f], 169 | [f, f, f, f]] 170 | ``` 171 | 172 | and `start = (3, 0) (bottom left)` and `end = (0, 0) (top left)`, the minimum number of steps required to reach the end is `7`, since we would need to go through `(1, 2)` because there is a wall everywhere else on the second row. 173 | 174 | ### Problem 22 175 | This problem was asked by Microsoft. 176 | 177 | Given a dictionary of words and a string made up of those words (no spaces), return the original sentence in a list. If there is more than one possible reconstruction, return any of them. If there is no possible reconstruction, then return null. 178 | 179 | For example, given the set of words `'quick', 'brown', 'the', 'fox'`, and the string `"thequickbrownfox"`, you should return `['the', 'quick', 'brown', 'fox']`. 180 | 181 | Given the set of words `'bed', 'bath', 'bedbath', 'and', 'beyond'`, and the string `"bedbathandbeyond"`, return either `['bed', 'bath', 'and', 'beyond]` or `['bedbath', 'and', 'beyond']`. 182 | 183 | 184 | ### Problem 21 185 | This problem was asked by Snapchat. 186 | 187 | Given an array of time intervals `(start, end)` for classroom lectures (possibly overlapping), find the minimum number of rooms required. 188 | 189 | For example, given `[(30, 75), (0, 50), (60, 150)]`, you should return 2. 190 | 191 | ### Problem 20 192 | This problem was asked by Google. 193 | 194 | Given two singly linked lists that intersect at some point, find the intersecting node. The lists are non-cyclical. 195 | 196 | For example, given `A = 1 -> 3 -> 7 -> 8 -> 10` and `B = 99 -> 1 -> 8 -> 10`, return the node with value 8. 197 | 198 | In this example, assume nodes with the same value are the exact same node objects. 199 | 200 | Do this in `O(M + N)` time (where M and N are the lengths of the lists) and constant space. 201 | 202 | ### Problem 19 203 | This problem was asked by Facebook. 204 | 205 | A builder is looking to build a row of `N` houses that can be of `K` different colors. He has a goal of minimizing cost while ensuring that no two neighboring houses are of the same color. 206 | 207 | Given an `N by K` matrix where the nth row and kth column represents the cost to build the nth house with kth color, return the minimum cost which achieves this goal. 208 | 209 | 210 | ### Problem 18 211 | This problem was asked by Google. 212 | 213 | Given an array of integers and a number `k`, where `1 <= k <= length` of the array, compute the maximum values of each subarray of length `k`. 214 | 215 | For example, given `array = [10, 5, 2, 7, 8, 7]` and `k = 3`, we should get: `[10, 7, 8, 8]`, since: 216 | 217 | ``` 218 | 10 = max(10, 5, 2) 219 | 7 = max(5, 2, 7) 220 | 8 = max(2, 7, 8) 221 | 8 = max(7, 8, 7) 222 | ``` 223 | 224 | Do this in `O(n)` time and `O(k)` space. You can modify the input array in-place and you do not need to store the results. You can simply print them out as you compute them. 225 | 226 | ### Problem 17 227 | This problem was asked by Google. 228 | 229 | Suppose we represent our file system by a string in the following manner: 230 | 231 | The string `"dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext"` represents: 232 | ``` 233 | dir 234 | subdir1 235 | subdir2 236 | file.ext 237 | ``` 238 | The directory `dir` contains an empty sub-directory `subdir1` and a sub-directory `subdir2` containing a file `file.ext`. 239 | 240 | The string `"dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"` represents: 241 | 242 | ``` 243 | dir 244 | subdir1 245 | file1.ext 246 | subsubdir1 247 | subdir2 248 | subsubdir2 249 | file2.ext 250 | ``` 251 | 252 | The directory `dir` contains two sub-directories `subdir1` and `subdir2`. `subdir1` contains a file `file1.ext` and an empty second-level sub-directory `subsubdir1`. `subdir2` contains a second-level sub-directory `subsubdir2` containing a file `file2.ext`. 253 | 254 | We are interested in finding the longest (number of characters) absolute path to a file within our file system. For example, in the second example above, the longest absolute path is `"dir/subdir2/subsubdir2/file2.ext"`, and its length is 32 (not including the double quotes). 255 | 256 | Given a string representing the file system in the above format, return the length of the longest absolute path to a file in the abstracted file system. If there is no file in the system, return 0. 257 | 258 | Note: 259 | 260 | The name of a file contains at least a period and an extension. 261 | 262 | The name of a directory or sub-directory will not contain a period. 263 | 264 | ### Problem 16 265 | This problem was asked by Twitter. 266 | 267 | You run an e-commerce website and want to record the last N order ids in a log. Implement a data structure to accomplish this, with the following API: 268 | ``` 269 | record(order_id): adds the order_id to the log 270 | get_last(i): gets the ith last element from the log. i is guaranteed to be smaller than or equal to N. 271 | ``` 272 | You should be as efficient with time and space as possible. 273 | 274 | ### Problem 15 275 | This problem was asked by Facebook. 276 | 277 | Given a stream of elements too large to store in memory, pick a random element from the stream with uniform probability. 278 | 279 | ### Problem 14 280 | This problem was asked by Google. 281 | 282 | The area of a circle is defined as πr2. Estimate π to 3 decimal places using a Monte Carlo method. 283 | 284 | Hint: The basic equation of a circle is x2 + y2 = r2. 285 | 286 | ### Problem 13 287 | This problem was asked by Amazon. 288 | 289 | Given an integer k and a string s, find the length of the longest substring that contains at most k distinct characters. 290 | 291 | For example, given s = `"abcba"` and k = 2, the longest substring with k distinct characters is `"bcb"`. 292 | 293 | ### Problem 12 294 | This problem was asked by Amazon. 295 | 296 | There exists a staircase with N steps, and you can climb up either 1 or 2 steps at a time. Given N, write a function that returns the number of unique ways you can climb the staircase. The order of the steps matters. 297 | 298 | For example, if N is 4, then there are 5 unique ways: 299 | ``` 300 | 1, 1, 1, 1 301 | 2, 1, 1 302 | 1, 2, 1 303 | 1, 1, 2 304 | 2, 2 305 | ``` 306 | What if, instead of being able to climb 1 or 2 steps at a time, you could climb any number from a set of positive integers X? For example, if `X = {1, 3, 5}`, you could climb 1, 3, or 5 steps at a time. 307 | 308 | ### Problem 11 309 | This problem was asked by Twitter. 310 | 311 | Implement an autocomplete system. That is, given a query string s and a set of all possible query strings, return all strings in the set that have s as a prefix. 312 | 313 | For example, given the query string de and the set of strings `[dog, deer, deal]`, return `[deer, deal]`. 314 | 315 | Hint: Try preprocessing the dictionary into a more efficient data structure to speed up queries. 316 | 317 | ### Problem 10 318 | This problem was asked by Apple. 319 | 320 | Implement a job scheduler which takes in a function f and an integer n, and calls f after n milliseconds. 321 | 322 | ### Problem 9 323 | This problem was asked by Airbnb. 324 | 325 | Given a list of integers, write a function that returns the largest sum of non-adjacent numbers. Numbers can be 0 or negative. 326 | 327 | For example, [2, 4, 6, 2, 5] should return 13, since we pick 2, 6, and 5. [5, 1, 1, 5] should return 10, since we pick 5 and 5. 328 | 329 | Follow-up: Can you do this in O(N) time and constant space? 330 | 331 | ### Problem 8 332 | This problem was asked by Google. 333 | 334 | A unival tree (which stands for "universal value") is a tree where all nodes under it have the same value. 335 | 336 | Given the root to a binary tree, count the number of unival subtrees. 337 | 338 | For example, the following tree has 5 unival subtrees: 339 | ``` 340 | 0 341 | / \ 342 | 1 0 343 | / \ 344 | 1 0 345 | / \ 346 | 1 1 347 | ``` 348 | 349 | ### Problem 7 350 | This problem was asked by Facebook. 351 | 352 | Given the mapping a = 1, b = 2, ... z = 26, and an encoded message, count the number of ways it can be decoded. 353 | 354 | For example, the message '111' would give 3, since it could be decoded as 'aaa', 'ka', and 'ak'. 355 | 356 | You can assume that the messages are decodable. For example, '001' is not allowed. 357 | 358 | (Not sure if '10001' is valid) 359 | 360 | > Question: How do deal with 0 if there are any? 361 | 362 | > Let's just assume there is no ZERO in the message; 363 | 364 | ### Problem 6 365 | This problem was asked by Google. 366 | 367 | An XOR linked list is a more memory efficient doubly linked list. Instead of each node holding next and prev fields, it holds a field named both, which is a XOR of the next node and the previous node. Implement a XOR linked list; it has an add(element) which adds the element to the end, and a get(index) which returns the node at index. 368 | 369 | If using a language that has no pointers (such as Python), you can assume you have access to 'get_pointer' and 'dereference_pointer' functions that converts between nodes and memory addresses. 370 | 371 | ### Problem 5 372 | This problem was asked by Jane Street. 373 | 374 | `cons(a, b)` constructs a pair, and `car(pair)` and `cdr(pair)` returns the first and last element of that pair. For example, `car(cons(3, 4))` returns 3, and `cdr(cons(3, 4))` returns 4. 375 | 376 | Given this implementation of cons: 377 | ``` 378 | def cons(a, b): 379 | def pair(f): 380 | return f(a, b) 381 | return pair 382 | ``` 383 | Implement car and cdr. 384 | 385 | ### Problem 4 386 | This problem was asked by Stripe. 387 | 388 | Given an array of integers, find the first missing positive integer in linear time and constant space. In other words, find the lowest positive integer that does not exist in the array. The array can contain duplicates and negative numbers as well. 389 | 390 | For example, the input `[3, 4, -1, 1]` should give 2. The input `[1, 2, 0]` should give 3. 391 | 392 | You can modify the input array in-place. 393 | 394 | Some other thoughts: 395 | 396 | > A naive method to solve this problem is to search all positive integers, starting from 1 in the given array. We may have to search at most n+1 numbers in the given array. So this solution takes O(n^2) in worst case. 397 | 398 | > We can use sorting to solve it in lesser time complexity. We can sort the array in O(nLogn) time. Once the array is sorted, then all we need to do is a linear scan of the array. So this approach takes O(nLogn + n) time which is O(nLogn). 399 | 400 | > We can also use hashing. We can build a hash table of all positive elements in the given array. Once the hash table is built. We can look in the hash table for all positive integers, starting from 1. As soon as we find a number which is not there in hash table, we return it. This approach may take O(n) time on average, but it requires O(n) extra space. 401 | 402 | ### Problem 3 403 | This problem was asked by Google. 404 | 405 | Given the root to a binary tree, implement `serialize(root)`, which serializes the tree into a string, and `deserialize(s)`, which deserializes the string back into the tree. 406 | 407 | For example, given the following Node class 408 | ``` 409 | class Node: 410 | def __init__(self, val, left=None, right=None): 411 | self.val = val 412 | self.left = left 413 | self.right = right 414 | ``` 415 | The following test should pass: 416 | ``` 417 | node = Node('root', Node('left', Node('left.left')), Node('right')) 418 | assert deserialize(serialize(node)).left.left.val == 'left.left' 419 | ``` 420 | 421 | ### Problem 2 422 | This problem was asked by Uber. 423 | 424 | Given an array of integers, return a new array such that each element at index `i` of the new array is the product of all the numbers in the original array except the one at `i`. 425 | 426 | For example, if our input was `[1, 2, 3, 4, 5]`, the expected output would be `[120, 60, 40, 30, 24]`. If our input was `[3, 2, 1]`, the expected output would be `[2, 3, 6]`. 427 | 428 | Follow-up: what if you can't use division? 429 | 430 | ### Problem 1 431 | This problem was recently asked by Google. 432 | 433 | Given a list of numbers and a number `k`, return whether any two numbers from the list add up to `k`. 434 | 435 | For example, given `[10, 15, 3, 7]` and `k` of 17, return true since 10 + 7 is 17. 436 | 437 | Bonus: Can you do this in one pass? 438 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Daily Coding Problem 2 | Self-implemented solution for https://dailycodingproblem.com every day. 3 | 4 | Details of the problems, please refer to [problem descriptions](https://github.com/Jedshady/daily-coding-problem/blob/master/Problem%20Descriptions.md) 5 | --------------------------------------------------------------------------------