├── .gitignore ├── README.md ├── array ├── circular_counter.py ├── flatten.py ├── garage.py ├── longest_non_repeat.py ├── merge_intervals.py ├── missing_ranges.py ├── plus_one.py ├── rotate_array.py ├── summary_ranges.py ├── three_sum.py └── two_sum.py ├── backtrack ├── anagram.py ├── array_sum_combinations.py ├── combination_sum.py ├── expression_add_operators.py ├── factor_combinations.py ├── general_solution.md ├── generate_abbreviations.py ├── generate_parenthesis.py ├── letter_combination.py ├── palindrome_partitioning.py ├── pattern_match.py ├── permute.py ├── permute_unique.py ├── subsets.py ├── subsets_unique.py └── word_search.py ├── bfs ├── shortest_distance_from_all_buildings.py └── word_ladder.py ├── bit ├── add_without_operator.py ├── count_ones.py ├── power_of_two.py ├── reverse_bits.py ├── single_number.py ├── single_number2.py └── subsets.py ├── design ├── LRUcache.md ├── alarm_system.md ├── all_o_one_ds.md ├── calculator.md ├── excel_table.md ├── nearby_drivers.md ├── ride_sharing.md ├── task_runner.md └── twitter_feeds.md ├── dfs ├── all_factors.py ├── count_islands.py ├── pacific_atlantic.py ├── sudoku_solver.py └── walls_and_gates.py ├── dp ├── buy_sell_stock.py ├── climbing_stairs.py ├── combination_sum.py ├── house_robber.py ├── longest_increasing.py ├── max_product_subarray.py ├── max_subarray.py ├── num_decodings.py ├── regex_matching.py └── word_break.py ├── graph ├── clone_graph.py ├── find_path.py ├── graph.py └── traversal.py ├── heap ├── merge_sorted_k_lists.py ├── skyline.py └── sliding_window_max.py ├── linkedlist ├── add_two_numbers.py ├── copy_random_pointer.py ├── delete_node.py ├── first_cyclic_node.py ├── is_cyclic.py ├── is_palindrome.py ├── kth_to_last.py ├── linkedlist.py ├── remove_duplicates.py ├── reverse.py ├── rotate_list.py └── swap_in_pairs.py ├── map ├── hashtable.py ├── longest_common_subsequence.py ├── randomized_set.py └── valid_sudoku.py ├── math ├── extended_gcd.py ├── gcd.py ├── generate_strobogrammtic.py ├── is_strobogrammatic.py ├── nth_digit.py ├── prime_test.py ├── primes_sieve_of_eratosthenes.py ├── pythagoras.py ├── rabin_miller.py ├── rsa.py └── sqrt_precision_factor.py ├── matrix ├── bomb_enemy.py ├── matrix_rotation.txt ├── rotate_image.py ├── sparse_dot_vector.py ├── sparse_mul.py └── spiral_traversal.py ├── queue ├── __init__.py ├── max_sliding_window.py ├── moving_average.py ├── queue.py ├── reconstruct_queue.py └── zigzagiterator.py ├── search ├── binary_search.py ├── count_elem.py ├── first_occurance.py └── last_occurance.py ├── set └── randomized_set.py ├── sort ├── insertion_sort.py ├── meeting_rooms.py ├── merge_sort.py ├── quick_sort.py ├── selection_sort.py ├── sort_colors.py ├── topsort.py └── wiggle_sort.py ├── stack ├── __init__.py ├── longest_abs_path.py ├── simplify_path.py ├── stack.py └── valid_parenthesis.py ├── string ├── add_binary.py ├── breaking_bad.py ├── decode_string.py ├── encode_decode.py ├── group_anagrams.py ├── int_to_roman.py ├── is_palindrome.py ├── license_number.py ├── make_sentence.py ├── multiply_strings.py ├── one_edit_distance.py ├── rabin_karp.py ├── reverse_string.py ├── reverse_vowel.py ├── reverse_words.py ├── roman_to_int.py └── word_squares.py ├── tmp └── temporary.md ├── tree.md ├── tree ├── Segment_Tree │ └── segment_tree.py ├── binary_tree_paths.py ├── bintree2list.py ├── bst │ ├── BSTIterator.py │ ├── array2bst.py │ ├── bst_closest_value.py │ ├── delete_node.py │ ├── is_bst.py │ ├── kth_smallest.py │ ├── lowest_common_ancestor.py │ ├── predecessor.py │ ├── serialize_deserialize.py │ ├── successor.py │ └── unique_bst.py ├── deepest_left.py ├── invert_tree.py ├── is_balanced.py ├── is_subtree.py ├── is_symmetric.py ├── longest_consecutive.py ├── lowest_common_ancestor.py ├── max_height.py ├── max_path_sum.py ├── min_height.py ├── path_sum.py ├── path_sum2.py ├── pretty_print.py ├── same_tree.py ├── traversal │ ├── inorder.py │ ├── level_order.py │ └── zigzag.py ├── tree.py └── trie │ ├── add_and_search.py │ └── trie.py └── union-find └── count_islands.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.py[cod] 3 | -------------------------------------------------------------------------------- /array/circular_counter.py: -------------------------------------------------------------------------------- 1 | """ 2 | There are people sitting in a circular fashion, 3 | print every third member while removing them, 4 | the next counter starts immediately after the member is removed. 5 | Print till all the members are exhausted. 6 | 7 | For example: 8 | Input: consider 123456789 members sitting in a circular fashion, 9 | Output: 369485271 10 | """ 11 | 12 | a = ['1','2','3','4','5','6','7','8','9'] 13 | 14 | def josepheus(int_list, skip): 15 | skip = skip - 1 #list starts with 0 index 16 | idx = 0 17 | while len(int_list)>0: 18 | idx = (skip+idx)%len(int_list) #hashing to keep changing the index to every 3rd 19 | print(int_list.pop(idx)) 20 | 21 | 22 | josepheus(a,3) 23 | 24 | """ 25 | the reason for hashing is that we have to find the index of the item which needs to be removed. 26 | So for e.g. if you iterate with the initial list of folks with every 3rd item eliminated: 27 | 28 | INPUT 29 | int_list = 123456789 30 | skip = 3 31 | 32 | While Iteration: 33 | 34 | int_list = 123456789 35 | len(int_list) = 9 36 | skip = 2 # as int_list starts from 0 37 | idx = (0 + 2) % 9 #here previous index was 0 38 | so 3rd element which is 3 in this case eliminated 39 | int_list = 12456789 40 | len(int_list) = 8 41 | idx = (2 + 2) % 8 #here previous index was 2 42 | so 3rd element starting from 4th person which is 6 would be deleted. 43 | and so on 44 | The reason why we have to do this way is I am not putting the people who escape at the back of list so ideally in 2 while iteration the list should have been 45 | 45678912 and then no hashing needed to be done, which means you can directly remove the third element 46 | """ 47 | -------------------------------------------------------------------------------- /array/flatten.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement Flatten Arrays. 3 | Given an array that may contain nested arrays, 4 | give a single resultant array. 5 | 6 | function flatten(input){ 7 | } 8 | 9 | Example: 10 | 11 | Input: var input = [2, 1, [3, [4, 5], 6], 7, [8]]; 12 | flatten(input); 13 | Output: [2, 1, 3, 4, 5, 6, 7, 8] 14 | """ 15 | 16 | 17 | def list_flatten(l, a=None): 18 | a = list(a) if isinstance(a, (list, tuple)) else [] 19 | for i in l: 20 | if isinstance(i, (list, tuple)): 21 | a = list_flatten(i, a) 22 | else: 23 | a.append(i) 24 | return a 25 | 26 | 27 | # stack version 28 | # public static List flatten(List l) { 29 | # List main = new ArrayList(); 30 | # Stack> stack = new Stack>(); 31 | # Stack indexes = new Stack(); 32 | # stack.add(l); 33 | # indexes.add(0); 34 | # while (true) { 35 | # if (stack.isEmpty()) 36 | # break; 37 | # int index1 = indexes.pop(); 38 | # l = stack.pop(); 39 | # for (int i = index1; i < l.size(); i++) { 40 | # NestedList n = l.get(i); 41 | # if (n.isInteger()) { 42 | # main.add(n.value); 43 | # } else { 44 | # stack.add(l); 45 | # indexes.add(i+1); 46 | # l = n.list; 47 | # stack.add(l); 48 | # indexes.add(0); 49 | # break; 50 | 51 | # } 52 | # } 53 | # } 54 | 55 | # return main; 56 | # } 57 | -------------------------------------------------------------------------------- /array/garage.py: -------------------------------------------------------------------------------- 1 | # There is a parking lot with only one empty spot. Given the initial state 2 | # of the parking lot and the final state. Each step we are only allowed to 3 | # move a car 4 | # out of its place and move it into the empty spot. 5 | # The goal is to find out the least movement needed to rearrange 6 | # the parking lot from the initial state to the final state. 7 | 8 | # Say the initial state is an array: 9 | 10 | # [1,2,3,0,4], 11 | # where 1,2,3,4 are different cars, and 0 is the empty spot. 12 | 13 | # And the final state is 14 | 15 | # [0,3,2,1,4]. 16 | # We can swap 1 with 0 in the initial array to get [0,2,3,1,4] and so on. 17 | # Each step swap with 0 only. 18 | #Edited by cyberking-saga 19 | 20 | def garage(beg, end): 21 | i = 0 22 | moves = 0 23 | while beg != end: 24 | if beg[i] != 0 and beg[i] != end[i]: 25 | car = beg[i] 26 | empty = beg.index(0) 27 | final_pos = end.index(beg[i]) 28 | if empty != final_pos: 29 | beg[final_pos], beg[empty] = beg[empty], beg[final_pos] 30 | print(beg) 31 | empty = beg.index(0) 32 | beg[beg.index(car)], beg[empty] = beg[empty], beg[beg.index(car)] 33 | print(beg) 34 | moves += 2 35 | else: 36 | beg[beg.index(car)], beg[empty] = beg[empty], beg[beg.index(car)] 37 | print(beg) 38 | moves += 1 39 | i += 1 40 | if i == len(beg): 41 | i = 0 42 | return moves 43 | 44 | if __name__ == "__main__": 45 | initial = [1,2,3,0,4] 46 | final = [0,3,2,1,4] 47 | print("initial:", initial) 48 | print("final:", final) 49 | print(garage(initial, final)) 50 | -------------------------------------------------------------------------------- /array/longest_non_repeat.py: -------------------------------------------------------------------------------- 1 | # Given a string, find the length of the longest substring 2 | # without repeating characters. 3 | 4 | # Examples: 5 | 6 | # Given "abcabcbb", the answer is "abc", which the length is 3. 7 | 8 | # Given "bbbbb", the answer is "b", with the length of 1. 9 | 10 | # Given "pwwkew", the answer is "wke", with the length of 3. 11 | # Note that the answer must be a substring, 12 | # "pwke" is a subsequence and not a substring. 13 | 14 | def longest_non_repeat(s): 15 | start, maxlen = 0, 0 16 | used_char = {} 17 | for i, char in enumerate(s): 18 | if char in used_char and start <= used_char[char]: 19 | start = used_char[char] + 1 20 | else: 21 | maxlen = max(maxlen, i-start+1) 22 | used_char[char] = i 23 | return maxlen 24 | 25 | a = "abcabcdefbb" 26 | print(a) 27 | print(longest_non_repeat(a)) 28 | -------------------------------------------------------------------------------- /array/merge_intervals.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a collection of intervals, merge all overlapping intervals. 3 | 4 | For example, 5 | Given [1,3],[2,6],[8,10],[15,18], 6 | return [1,6],[8,10],[15,18]. 7 | """ 8 | 9 | # Definition for an interval. 10 | class Interval(object): 11 | def __init__(self, s=0, e=0): 12 | self.start = s 13 | self.end = e 14 | 15 | def merge(intervals): 16 | """ 17 | :type intervals: List[Interval] 18 | :rtype: List[Interval] 19 | """ 20 | out = [] 21 | for i in sorted(intervals, key=lambda i: i.start): 22 | if out and i.start <= out[-1].end: 23 | out[-1].end = max(out[-1].end, i.end) 24 | else: 25 | out += i, 26 | return out 27 | 28 | def print_intervals(intervals): 29 | res = [] 30 | for i in intervals: 31 | res.append('['+str(i.start)+','+str(i.end)+']') 32 | print("".join(res)) 33 | 34 | if __name__ == "__main__": 35 | given = [[1,3],[2,6],[8,10],[15,18]] 36 | intervals = [] 37 | for l, r in given: 38 | intervals.append(Interval(l,r)) 39 | print_intervals(intervals) 40 | print_intervals(merge(intervals)) 41 | -------------------------------------------------------------------------------- /array/missing_ranges.py: -------------------------------------------------------------------------------- 1 | ## find missing ranges between low and high in the given array. 2 | # ex) [3, 5] lo=1 hi=10 => answer: [1->2, 4, 6->10] 3 | 4 | def missing_ranges(nums, lo, hi): 5 | res = [] 6 | start = lo 7 | for num in nums: 8 | if num < start: 9 | continue 10 | if num == start: 11 | start += 1 12 | continue 13 | res.append(get_range(start, num-1)) 14 | start = num + 1 15 | if start <= hi: 16 | res.append(get_range(start, hi)) 17 | return res 18 | 19 | def get_range(n1, n2): 20 | if n1 == n2: 21 | return str(n1) 22 | else: 23 | return str(n1) + "->" + str(n2) 24 | 25 | nums = [3, 5, 10, 11, 12, 15, 19] 26 | print("original:", nums) 27 | print("missing range: ", missing_ranges(nums,0,20)) 28 | -------------------------------------------------------------------------------- /array/plus_one.py: -------------------------------------------------------------------------------- 1 | # Given a non-negative number represented as an array of digits, 2 | # plus one to the number. 3 | 4 | # The digits are stored such that the most significant 5 | # digit is at the head of the list. 6 | 7 | 8 | def plusOne(digits): 9 | """ 10 | :type digits: List[int] 11 | :rtype: List[int] 12 | """ 13 | digits[-1] = digits[-1] + 1 14 | res = [] 15 | ten = 0 16 | i = len(digits)-1 17 | while i >= 0 or ten == 1: 18 | sum = 0 19 | if i >= 0: 20 | sum += digits[i] 21 | if ten: 22 | sum += 1 23 | res.append(sum % 10) 24 | ten = sum / 10 25 | i -= 1 26 | return res[::-1] 27 | 28 | 29 | def plus_one(digits): 30 | n = len(digits) 31 | for i in range(n-1, -1, -1): 32 | if digits[i] < 9: 33 | digits[i] += 1 34 | return digits 35 | digits[i] = 0 36 | new_num = [0] * (n+1) 37 | new_num[0] = 1 38 | return new_num 39 | -------------------------------------------------------------------------------- /array/rotate_array.py: -------------------------------------------------------------------------------- 1 | """ 2 | Rotate an array of n elements to the right by k steps. 3 | 4 | For example, with n = 7 and k = 3, 5 | the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4]. 6 | 7 | Note: 8 | Try to come up as many solutions as you can, 9 | there are at least 3 different ways to solve this problem. 10 | """ 11 | 12 | 13 | def rotate(nums, k): 14 | """ 15 | :type nums: List[int] 16 | :type k: int 17 | :rtype: void Do not return anything, modify nums in-place instead. 18 | """ 19 | n = len(nums) 20 | k = k % n 21 | reverse(nums, 0, n - k - 1) 22 | reverse(nums, n - k, n - 1) 23 | reverse(nums, 0, n - 1) 24 | 25 | 26 | def reverse(array, a, b): 27 | while a < b: 28 | array[a], array[b] = array[b], array[a] 29 | a += 1 30 | b -= 1 31 | -------------------------------------------------------------------------------- /array/summary_ranges.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a sorted integer array without duplicates, 3 | return the summary of its ranges. 4 | 5 | For example, given [0,1,2,4,5,7], return ["0->2","4->5","7"]. 6 | """ 7 | 8 | 9 | def summary_ranges(nums): 10 | """ 11 | :type nums: List[int] 12 | :rtype: List[str] 13 | """ 14 | res = [] 15 | if len(nums) == 1: 16 | return [str(nums[0])] 17 | i = 0 18 | while i < len(nums): 19 | num = nums[i] 20 | while i+1 < len(nums) and nums[i+1] - nums[i] == 1: 21 | i += 1 22 | if nums[i] != num: 23 | res.append(str(num) + "->" + str(nums[i])) 24 | else: 25 | res.append(str(num)) 26 | i += 1 27 | return res 28 | -------------------------------------------------------------------------------- /array/three_sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array S of n integers, are there elements a, b, c in S 3 | such that a + b + c = 0? 4 | Find all unique triplets in the array which gives the sum of zero. 5 | 6 | Note: The solution set must not contain duplicate triplets. 7 | 8 | For example, given array S = [-1, 0, 1, 2, -1, -4], 9 | 10 | A solution set is: 11 | [ 12 | [-1, 0, 1], 13 | [-1, -1, 2] 14 | ] 15 | """ 16 | 17 | 18 | def three_sum(nums:"List[int]")->"List[int]": 19 | res = [] 20 | nums.sort() 21 | for i in range(len(nums)-2): 22 | if i > 0 and nums[i] == nums[i-1]: 23 | continue 24 | l, r = i+1, len(nums)-1 25 | while l < r: 26 | s = nums[i] + nums[l] + nums[r] 27 | if s > 0: 28 | r -= 1 29 | elif s < 0: 30 | l += 1 31 | else: 32 | # found three sum 33 | res.append((nums[i], nums[l], nums[r])) 34 | # remove duplicates 35 | while l < r and nums[l] == nums[l+1]: 36 | l+=1 37 | while l < r and nums[r] == nums[r-1]: 38 | r -= 1 39 | l += 1 40 | r -= 1 41 | return res 42 | 43 | 44 | if __name__ == "__main__": 45 | x = [-1,0,1,2,-1,-4] 46 | print(three_sum(x)) 47 | -------------------------------------------------------------------------------- /array/two_sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers, return indices of the two numbers 3 | such that they add up to a specific target. 4 | 5 | You may assume that each input would have exactly one solution, 6 | and you may not use the same element twice. 7 | 8 | Example: 9 | Given nums = [2, 7, 11, 15], target = 9, 10 | 11 | Because nums[0] + nums[1] = 2 + 7 = 9, 12 | return [0, 1]. 13 | """ 14 | 15 | 16 | def two_sum(nums:"List[int]", target:"int")->"List[int]": 17 | dic = {} 18 | for i, num in enumerate(nums): 19 | if num in dic: 20 | return [dic[num], i] 21 | else: 22 | dic[target - num] = i 23 | 24 | 25 | if __name__ == "__main__": 26 | arr = [3,2,4] 27 | target = 6 28 | res = two_sum(arr, target) 29 | print(res) 30 | -------------------------------------------------------------------------------- /backtrack/anagram.py: -------------------------------------------------------------------------------- 1 | def all_perms(elements): 2 | if len(elements) <=1: 3 | yield elements 4 | else: 5 | for perm in all_perms(elements[1:]): 6 | for i in range(len(elements)): 7 | yield perm[:i] + elements[0:1] + perm[i:] 8 | 9 | def all_perms(elements): 10 | if len(elements) <=1: 11 | return elements 12 | else: 13 | tmp = [] 14 | for perm in all_perms(elements[1:]): 15 | for i in range(len(elements)): 16 | tmp.append(perm[:i] + elements[0:1] + perm[i:]) 17 | return tmp 18 | 19 | word = "abc" 20 | print list(all_perms(word)) 21 | 22 | def anagram(s1,s2): 23 | c1 = [0]*26 24 | c2 = [0]*26 25 | 26 | for i in range(len(s1)): 27 | pos = ord(s1[i])-ord('a') 28 | c1[pos] = c1[pos] + 1 29 | 30 | for i in range(len(s2)): 31 | pos = ord(s2[i])-ord('a') 32 | c2[pos] = c2[pos] + 1 33 | 34 | j = 0 35 | stillOK = True 36 | while j<26 and stillOK: 37 | if c1[j]==c2[j]: 38 | j = j + 1 39 | else: 40 | stillOK = False 41 | 42 | return stillOK 43 | 44 | print(anagram('apple','pleap')) 45 | -------------------------------------------------------------------------------- /backtrack/array_sum_combinations.py: -------------------------------------------------------------------------------- 1 | """ 2 | WAP to take one element from each of the array add it to the target sum. Print all those three-element combinations. 3 | 4 | /* 5 | A = [1, 2, 3, 3] 6 | B = [2, 3, 3, 4] 7 | C = [1, 2, 2, 2] 8 | target = 7 9 | */ 10 | 11 | Result: 12 | [[1, 2, 4], [1, 3, 3], [1, 3, 3], [1, 3, 3], [1, 3, 3], [1, 4, 2], [2, 2, 3], [2, 2, 3], [2, 3, 2], [2, 3, 2], [3, 2, 2], [3, 2, 2]] 13 | """ 14 | 15 | 16 | A = [1, 2, 3, 3] 17 | B = [2, 3, 3, 4] 18 | C = [1, 2, 2, 2] 19 | target = 7 20 | 21 | def construct_candidates(constructed_sofar): 22 | global A,B,C 23 | array = A 24 | if 1 == len(constructed_sofar) : 25 | array = B 26 | elif 2 == len(constructed_sofar) : 27 | array = C 28 | return array 29 | 30 | 31 | def over(constructed_sofar): 32 | global target 33 | sum = 0 34 | to_stop, reached_target = False, False 35 | for elem in constructed_sofar: 36 | sum += elem 37 | if sum >= target or len(constructed_sofar) >= 3 : 38 | to_stop = True 39 | if sum == target and 3 == len(constructed_sofar): 40 | reached_target = True 41 | 42 | return to_stop, reached_target 43 | 44 | def backtrack(constructed_sofar): 45 | to_stop, reached_target = over(constructed_sofar) 46 | if to_stop: 47 | if reached_target : 48 | print constructed_sofar 49 | return 50 | candidates = construct_candidates(constructed_sofar) 51 | for candidate in candidates : 52 | constructed_sofar.append(candidate) 53 | backtrack(constructed_sofar[:]) 54 | constructed_sofar.pop() 55 | backtrack([]) 56 | 57 | 58 | # Complexity: O(n(m+p)) 59 | 60 | # 1. Sort all the arrays - a,b,c. - This will improve average time complexity. 61 | # 2. If c[i] < Sum, then look for Sum - c[i] in array a and b. When pair found, insert c[i], a[j] & b[k] into the result list. This can be done in O(n). 62 | # 3. Keep on doing the above procedure while going through complete c array. 63 | 64 | 65 | import itertools 66 | from functools import partial 67 | A = [1,2,3,3] 68 | B = [2,3,3,4] 69 | C = [1,2,2,2] 70 | S = 7 71 | 72 | def check_sum(N, *nums): 73 | if sum(x for x in nums) == N: 74 | return (True, nums) 75 | else: 76 | return (False, nums) 77 | 78 | pro = itertools.product(A,B,C) 79 | func = partial(check_sum, S) 80 | sums = list(itertools.starmap(func, pro)) 81 | 82 | res = set() 83 | for s in sums: 84 | if s[0] == True and s[1] not in res: 85 | res.add(s[1]) 86 | print res 87 | -------------------------------------------------------------------------------- /backtrack/combination_sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a set of candidate numbers (C) (without duplicates) and a target number 3 | (T), find all unique combinations in C where the candidate numbers sums to T. 4 | 5 | The same repeated number may be chosen from C unlimited number of times. 6 | 7 | Note: 8 | All numbers (including target) will be positive integers. 9 | The solution set must not contain duplicate combinations. 10 | For example, given candidate set [2, 3, 6, 7] and target 7, 11 | A solution set is: 12 | [ 13 | [7], 14 | [2, 2, 3] 15 | ] 16 | """ 17 | 18 | def combinationSum(self, candidates, target): 19 | res = [] 20 | candidates.sort() 21 | self.dfs(candidates, target, 0, [], res) 22 | return res 23 | 24 | def dfs(self, nums, target, index, path, res): 25 | if target < 0: 26 | return # backtracking 27 | if target == 0: 28 | res.append(path) 29 | return 30 | for i in range(index, len(nums)): 31 | self.dfs(nums, target-nums[i], i, path+[nums[i]], res) 32 | -------------------------------------------------------------------------------- /backtrack/expression_add_operators.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string that contains only digits 0-9 and a target value, 3 | return all possibilities to add binary operators (not unary) +, -, or * 4 | between the digits so they prevuate to the target value. 5 | 6 | Examples: 7 | "123", 6 -> ["1+2+3", "1*2*3"] 8 | "232", 8 -> ["2*3+2", "2+3*2"] 9 | "105", 5 -> ["1*0+5","10-5"] 10 | "00", 0 -> ["0+0", "0-0", "0*0"] 11 | "3456237490", 9191 -> [] 12 | """ 13 | 14 | def add_operator(num, target): 15 | """ 16 | :type num: str 17 | :type target: int 18 | :rtype: List[str] 19 | """ 20 | res = [] 21 | if not num: return res 22 | helper(res, "", num, target, 0, 0, 0) 23 | return res 24 | 25 | def helper(res, path, num, target, pos, prev, multed): 26 | if pos == len(num): 27 | if (target == prev): 28 | res.append(path) 29 | return 30 | for i in range(pos, len(num)): 31 | if i != pos and num[pos] == '0': # all digits have to be used 32 | break 33 | cur = int(num[pos:i+1]) 34 | if pos == 0: 35 | helper(res, path + str(cur), num, target, i+1, cur, cur) 36 | else: 37 | helper(res, path + "+" + str(cur), num, target, i+1, prev + cur, cur) 38 | helper(res, path + "-" + str(cur), num, target, i+1, prev - cur, -cur) 39 | helper(res, path + "*" + str(cur), num, target, i+1, prev - multed + multed * cur, multed * cur) 40 | 41 | 42 | # "123", 6 -> ["1+2+3", "1*2*3"] 43 | s = "123" 44 | target = 6 45 | print(add_operator(s, target)) 46 | # "232", 8 -> ["2*3+2", "2+3*2"] 47 | s = "232" 48 | target = 8 49 | print(add_operator(s, target)) 50 | 51 | s = "123045" 52 | target = 3 53 | print(add_operator(s, target)) 54 | -------------------------------------------------------------------------------- /backtrack/factor_combinations.py: -------------------------------------------------------------------------------- 1 | """ 2 | Numbers can be regarded as product of its factors. For example, 3 | 4 | 8 = 2 x 2 x 2; 5 | = 2 x 4. 6 | Write a function that takes an integer n and return all possible combinations of its factors. 7 | 8 | Note: 9 | You may assume that n is always positive. 10 | Factors should be greater than 1 and less than n. 11 | Examples: 12 | input: 1 13 | output: 14 | [] 15 | input: 37 16 | output: 17 | [] 18 | input: 12 19 | output: 20 | [ 21 | [2, 6], 22 | [2, 2, 3], 23 | [3, 4] 24 | ] 25 | input: 32 26 | output: 27 | [ 28 | [2, 16], 29 | [2, 2, 8], 30 | [2, 2, 2, 4], 31 | [2, 2, 2, 2, 2], 32 | [2, 4, 4], 33 | [4, 8] 34 | ] 35 | """ 36 | 37 | # Iterative: 38 | 39 | def getFactors(self, n): 40 | todo, combis = [(n, 2, [])], [] 41 | while todo: 42 | n, i, combi = todo.pop() 43 | while i * i <= n: 44 | if n % i == 0: 45 | combis += combi + [i, n/i], 46 | todo += (n/i, i, combi+[i]), 47 | i += 1 48 | return combis 49 | 50 | # Recursive: 51 | 52 | def getFactors(self, n): 53 | def factor(n, i, combi, combis): 54 | while i * i <= n: 55 | if n % i == 0: 56 | combis += combi + [i, n/i], 57 | factor(n/i, i, combi+[i], combis) 58 | i += 1 59 | return combis 60 | return factor(n, 2, [], []) 61 | -------------------------------------------------------------------------------- /backtrack/generate_abbreviations.py: -------------------------------------------------------------------------------- 1 | """ 2 | given input word, return the list of abbreviations. 3 | ex) 4 | word => [1ord, w1rd, wo1d, w2d, 3d, w3 ... etc] 5 | """ 6 | 7 | 8 | def generate_abbreviations(word): 9 | result = [] 10 | backtrack(result, word, 0, 0, "") 11 | return result 12 | 13 | 14 | def backtrack(result, word, pos, count, cur): 15 | if pos == len(word): 16 | if count > 0: 17 | cur += str(count) 18 | result.append(cur) 19 | return 20 | 21 | if count > 0: # add the current word 22 | backtrack(result, word, pos+1, 0, cur+str(count)+word[pos]) 23 | else: 24 | backtrack(result, word, pos+1, 0, cur+word[pos]) 25 | # skip the current word 26 | backtrack(result, word, pos+1, count+1, cur) 27 | -------------------------------------------------------------------------------- /backtrack/generate_parenthesis.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given n pairs of parentheses, write a function to generate 3 | all combinations of well-formed parentheses. 4 | 5 | For example, given n = 3, a solution set is: 6 | 7 | [ 8 | "((()))", 9 | "(()())", 10 | "(())()", 11 | "()(())", 12 | "()()()" 13 | ] 14 | """ 15 | 16 | def gen_parenthesis(n:"int")->"List[str]": 17 | res = [] 18 | add_pair(res, "", n, 0) 19 | return res 20 | 21 | def add_pair(res, s, left, right): 22 | if left == 0 and right == 0: 23 | res.append(s) 24 | return 25 | if right > 0: 26 | add_pair(res, s+")", left, right-1) 27 | if left > 0: 28 | add_pair(res, s+"(", left-1, right+1) 29 | 30 | 31 | if __name__=="__main__": 32 | print(gen_parenthesis(3)) 33 | -------------------------------------------------------------------------------- /backtrack/letter_combination.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a digit string, return all possible letter 3 | combinations that the number could represent. 4 | 5 | Input:Digit string "23" 6 | Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. 7 | """ 8 | 9 | 10 | def letter_combinations(digits:"str")->"List[str]": 11 | if digits == "": 12 | return [] 13 | kmaps = { 14 | "2": "abc", 15 | "3": "def", 16 | "4": "ghi", 17 | "5": "jkl", 18 | "6": "mno", 19 | "7": "pqrs", 20 | "8": "tuv", 21 | "9": "wxyz" 22 | } 23 | ans = [""] 24 | for num in digits: 25 | tmp = [] 26 | for an in ans: 27 | for char in kmaps[num]: 28 | tmp.append(an + char) 29 | ans = tmp 30 | return ans 31 | 32 | 33 | if __name__ == "__main__": 34 | digit_string = "23" 35 | print(letter_combinations(digit_string)) 36 | -------------------------------------------------------------------------------- /backtrack/palindrome_partitioning.py: -------------------------------------------------------------------------------- 1 | # It looks like you need to be looking not for all palindromic substrings, but rather for all the ways you can divide the input string up into palindromic substrings. (There's always at least one way, since one-character substrings are always palindromes.) 2 | 3 | # Here's the way I've done it: 4 | 5 | def palindromic_substrings(s): 6 | if not s: 7 | return [[]] 8 | results = [] 9 | for i in range(len(s), 0, -1): 10 | sub = s[:i] 11 | if sub == sub[::-1]: 12 | for rest in palindromic_substrings(s[i:]): 13 | results.append([sub] + rest) 14 | return results 15 | 16 | # There's two loops. 17 | # The outer loop checks each length of initial substring (in descending length order) to see if it is a palindrome. If so, it recurses on the rest of the string and loops over the returned values, adding the initial substring to each item before adding it to the results. 18 | 19 | # A slightly more Pythonic approach would be to make a recursive generator: 20 | 21 | def palindromic_substrings(s): 22 | if not s: 23 | yield [] 24 | return 25 | for i in range(len(s), 0, -1): 26 | sub = s[:i] 27 | if sub == sub[::-1]: 28 | for rest in palindromic_substrings(s[i:]): 29 | yield [sub] + rest 30 | -------------------------------------------------------------------------------- /backtrack/pattern_match.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a pattern and a string str, 3 | find if str follows the same pattern. 4 | 5 | Here follow means a full match, such that there is a bijection between 6 | a letter in pattern and a non-empty substring in str. 7 | 8 | Examples: 9 | pattern = "abab", str = "redblueredblue" should return true. 10 | pattern = "aaaa", str = "asdasdasdasd" should return true. 11 | pattern = "aabb", str = "xyzabcxzyabc" should return false. 12 | Notes: 13 | You may assume both pattern and str contains only lowercase letters. 14 | """ 15 | 16 | 17 | def pattern_match(pattern, string): 18 | """ 19 | :type pattern: str 20 | :type string: str 21 | :rtype: bool 22 | """ 23 | return backtrack(pattern, string, {}) 24 | 25 | 26 | def backtrack(pattern, string, dic): 27 | print(dic) 28 | if len(pattern) == 0 and len(string) > 0: 29 | return False 30 | if len(pattern) == len(string) == 0: 31 | return True 32 | for end in range(1, len(string)-len(pattern)+2): 33 | if pattern[0] not in dic and string[:end] not in dic.values(): 34 | dic[pattern[0]] = string[:end] 35 | if backtrack(pattern[1:], string[end:], dic): 36 | return True 37 | del dic[pattern[0]] 38 | elif pattern[0] in dic and dic[pattern[0]] == string[:end]: 39 | if backtrack(pattern[1:], string[end:], dic): 40 | return True 41 | return False 42 | 43 | if __name__ == "__main__": 44 | pattern1 = "abab" 45 | string1 = "redblueredblue" 46 | pattern2 = "aaaa" 47 | string2 = "asdasdasdasd" 48 | pattern3 = "aabb" 49 | string3 = "xyzabcxzyabc" 50 | print(pattern_match(pattern1, string1)) 51 | print(pattern_match(pattern2, string2)) 52 | print(pattern_match(pattern3, string3)) 53 | -------------------------------------------------------------------------------- /backtrack/permute.py: -------------------------------------------------------------------------------- 1 | # Given a collection of distinct numbers, return all possible permutations. 2 | 3 | # For example, 4 | # [1,2,3] have the following permutations: 5 | # [ 6 | # [1,2,3], 7 | # [1,3,2], 8 | # [2,1,3], 9 | # [2,3,1], 10 | # [3,1,2], 11 | # [3,2,1] 12 | # ] 13 | 14 | def permute(nums): 15 | perms = [[]] 16 | for n in nums: 17 | new_perms = [] 18 | for perm in perms: 19 | for i in range(len(perm)+1): 20 | new_perms.append(perm[:i] + [n] + perm[i:]) ###insert n 21 | print(i, perm[:i], [n], perm[i:], ">>>>", new_perms) 22 | perms = new_perms 23 | return perms 24 | 25 | # DFS Version 26 | # def permute(nums): 27 | # res = [] 28 | # dfs(res, nums, []) 29 | # return res 30 | 31 | # def dfs(res, nums, path): 32 | # if not nums: 33 | # res.append(path) 34 | # for i in range(len(nums)): 35 | # print(nums[:i]+nums[i+1:]) 36 | # dfs(res, nums[:i]+nums[i+1:], path+[nums[i]]) 37 | 38 | test = [1,2,3] 39 | print(test) 40 | print(permute(test)) 41 | -------------------------------------------------------------------------------- /backtrack/permute_unique.py: -------------------------------------------------------------------------------- 1 | # Given a collection of numbers that might contain duplicates, 2 | # return all possible unique permutations. 3 | 4 | # For example, 5 | # [1,1,2] have the following unique permutations: 6 | # [ 7 | # [1,1,2], 8 | # [1,2,1], 9 | # [2,1,1] 10 | # ] 11 | 12 | def permute_unique(nums): 13 | perms = [[]] 14 | for n in nums: 15 | new_perms = [] 16 | for l in perms: 17 | for i in range(len(l)+1): 18 | new_perms.append(l[:i]+[n]+l[i:]) 19 | if i= len(nums): 44 | # res.append(cur) 45 | # else: 46 | # backtrack(res, nums, cur+[nums[pos]], pos+1) 47 | # backtrack(res, nums, cur, pos+1) 48 | 49 | 50 | # Iteratively 51 | def subsets2(self, nums): 52 | res = [[]] 53 | for num in sorted(nums): 54 | res += [item+[num] for item in res] 55 | return res 56 | 57 | test = [1,2,3] 58 | print(test) 59 | print(subsets(test)) 60 | -------------------------------------------------------------------------------- /backtrack/subsets_unique.py: -------------------------------------------------------------------------------- 1 | # Given a collection of integers that might contain duplicates, nums, 2 | # return all possible subsets. 3 | 4 | # Note: The solution set must not contain duplicate subsets. 5 | 6 | # For example, 7 | # If nums = [1,2,2], a solution is: 8 | 9 | # [ 10 | # [2], 11 | # [1], 12 | # [1,2,2], 13 | # [2,2], 14 | # [1,2], 15 | # [] 16 | # ] 17 | 18 | def subsets_unique(nums): 19 | res = set() 20 | backtrack(res, nums, [], 0) 21 | return list(res) 22 | 23 | def backtrack(res, nums, stack, pos): 24 | if pos == len(nums): 25 | res.add(tuple(stack)) 26 | else: 27 | # take 28 | stack.append(nums[pos]) 29 | backtrack(res, nums, stack, pos+1) 30 | stack.pop() 31 | 32 | # don't take 33 | backtrack(res, nums, stack, pos+1) 34 | 35 | 36 | test = [1,2,2] 37 | print(test) 38 | print(subsets_unique(test)) 39 | -------------------------------------------------------------------------------- /backtrack/word_search.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | ''' 3 | Given a matrix of words and a list of words to search, return a list of words that exists in the board 4 | This is Word Search II on LeetCode 5 | 6 | board = [ 7 | ['o','a','a','n'], 8 | ['e','t','a','e'], 9 | ['i','h','k','r'], 10 | ['i','f','l','v'] 11 | ] 12 | 13 | words = ["oath","pea","eat","rain"] 14 | 15 | ''' 16 | 17 | def find_words(board, words): 18 | # make a trie structure that is essentially dictionaries of dictionaries that map each character to a potential next character 19 | trie = {} 20 | for word in words: 21 | curr_trie = trie 22 | for char in word: 23 | if char not in curr_trie: 24 | curr_trie[char] = {} 25 | curr_trie = curr_trie[char] 26 | curr_trie['#'] = '#' 27 | 28 | # result is a set of found words since we do not want repeats 29 | result = set() 30 | used = [[False]*len(board[0]) for _ in range(len(board))] 31 | 32 | for i in range(len(board)): 33 | for j in range(len(board[0])): 34 | backtrack(board, i, j, trie, '', used, result) 35 | return list(result) 36 | 37 | ''' 38 | backtrack tries to build each words from the board and return all words found 39 | @param: board, the passed in board of characters 40 | @param: i, the row index 41 | @param: j, the column index 42 | @param: trie, a trie of the passed in words 43 | @param: pre, a buffer of currently build string that differs by recursion stack 44 | @param: used, a replica of the board except in booleans to state whether a character has been used 45 | @param: result, the resulting set that contains all words found 46 | 47 | @return: list of words found 48 | ''' 49 | 50 | def backtrack(board, i, j, trie, pre, used, result): 51 | if '#' in trie: 52 | result.add(pre) 53 | 54 | if i < 0 or i >= len(board) or j < 0 or j >= len(board[0]): 55 | return 56 | 57 | if not used[i][j] and board[i][j] in trie: 58 | used[i][j]=True 59 | backtrack(board,i+1,j,trie[board[i][j]],pre+board[i][j], used, result) 60 | backtrack(board,i,j+1,trie[board[i][j]],pre+board[i][j], used, result) 61 | backtrack(board,i-1,j,trie[board[i][j]],pre+board[i][j], used, result) 62 | backtrack(board,i,j-1,trie[board[i][j]],pre+board[i][j], used, result) 63 | used[i][j]=False 64 | 65 | class MyTests(unittest.TestCase): 66 | def test_normal(self): 67 | board = [ 68 | ['o','a','a','n'], 69 | ['e','t','a','e'], 70 | ['i','h','k','r'], 71 | ['i','f','l','v'] 72 | ] 73 | 74 | words = ["oath","pea","eat","rain"] 75 | self.assertEqual(find_words(board, words), ['oath', 'eat']) 76 | 77 | def test_none(self): 78 | board = [ 79 | ['o','a','a','n'], 80 | ['e','t','a','e'], 81 | ['i','h','k','r'], 82 | ['i','f','l','v'] 83 | ] 84 | 85 | words = ["chicken", "nugget", "hello", "world"] 86 | self.assertEqual(find_words(board, words), []) 87 | 88 | def test_empty(self): 89 | board = [] 90 | words = [] 91 | self.assertEqual(find_words(board, words), []) 92 | 93 | def test_uneven(self): 94 | board = [ 95 | ['o','a','a','n'], 96 | ['e','t','a','e'] 97 | ] 98 | words = ["oath","pea","eat","rain"] 99 | self.assertEqual(find_words(board, words), ['eat']) 100 | 101 | def test_repeat(self): 102 | board = [ 103 | ['a','a','a'], 104 | ['a','a','a'], 105 | ['a','a','a'] 106 | ] 107 | words = ["a", "aa", "aaa", "aaaa", "aaaaa"] 108 | self.assertTrue(len(find_words(board, words))==5) 109 | 110 | if __name__=="__main__": 111 | unittest.main() 112 | -------------------------------------------------------------------------------- /bfs/shortest_distance_from_all_buildings.py: -------------------------------------------------------------------------------- 1 | import collections 2 | 3 | """ 4 | do BFS from each building, and decrement all empty place for every building visit 5 | when grid[i][j] == -b_nums, it means that grid[i][j] are already visited from all b_nums 6 | and use dist to record distances from b_nums 7 | """ 8 | 9 | def shortest_distance(grid): 10 | if not grid or not grid[0]: 11 | return -1 12 | 13 | matrix = [[[0,0] for i in range(len(grid[0]))] for j in range(len(grid))] 14 | 15 | count = 0 # count how many building we have visited 16 | for i in range(len(grid)): 17 | for j in range(len(grid[0])): 18 | if grid[i][j] == 1: 19 | bfs(grid, matrix, i, j, count) 20 | count += 1 21 | 22 | res = float('inf') 23 | for i in range(len(matrix)): 24 | for j in range(len(matrix[0])): 25 | if matrix[i][j][1]==count: 26 | res = min(res, matrix[i][j][0]) 27 | 28 | return res if res!=float('inf') else -1 29 | 30 | def bfs(grid, matrix, i, j, count): 31 | q = [(i, j, 0)] 32 | while q: 33 | i, j, step = q.pop(0) 34 | for k, l in [(i-1,j), (i+1,j), (i,j-1), (i,j+1)]: 35 | # only the position be visited by count times will append to queue 36 | if 0<=k "hot" -> "dot" -> "dog" -> "cog", 15 | return its length 5. 16 | . 17 | Note: 18 | Return 0 if there is no such transformation sequence. 19 | All words have the same length. 20 | All words contain only lowercase alphabetic characters. 21 | """ 22 | def ladderLength(beginWord, endWord, wordList): 23 | """ 24 | Bidirectional BFS!!! 25 | :type beginWord: str 26 | :type endWord: str 27 | :type wordList: Set[str] 28 | :rtype: int 29 | """ 30 | beginSet = set() 31 | endSet = set() 32 | beginSet.add(beginWord) 33 | endSet.add(endWord) 34 | result = 2 35 | while len(beginSet) != 0 and len(endSet) != 0: 36 | if len(beginSet) > len(endSet): 37 | beginSet, endSet = endSet, beginSet 38 | nextBeginSet = set() 39 | for word in beginSet: 40 | for ladderWord in wordRange(word): 41 | if ladderWord in endSet: 42 | return result 43 | if ladderWord in wordList: 44 | nextBeginSet.add(ladderWord) 45 | wordList.remove(ladderWord) 46 | beginSet = nextBeginSet 47 | result += 1 48 | print(beginSet) 49 | print(result) 50 | return 0 51 | 52 | def wordRange(word): 53 | for ind in range(len(word)): 54 | tempC = word[ind] 55 | for c in [chr(x) for x in range(ord('a'), ord('z')+1)]: 56 | if c != tempC: 57 | yield word[:ind] + c + word[ind+1:] 58 | 59 | beginWord = "hit" 60 | endWord = "cog" 61 | wordList = ["hot","dot","dog","lot","log"] 62 | print(ladderLength(beginWord, endWord, wordList)) 63 | -------------------------------------------------------------------------------- /bit/add_without_operator.py: -------------------------------------------------------------------------------- 1 | """ 2 | The following code adds two numbers without using the '+' operator. 3 | The code uses bitwise operations to add two numbers. 4 | 5 | Input: 2 3 6 | Output: 5 7 | """ 8 | 9 | def addWithoutOperator(x, y): 10 | while y != 0: 11 | carry = x & y 12 | x = x ^ y 13 | y = carry << 1 14 | print x 15 | 16 | def main(): 17 | x,y = map(int,raw_input().split()) 18 | addWithoutOperator(x,y) 19 | 20 | if __name__ == '__main__': 21 | main() 22 | -------------------------------------------------------------------------------- /bit/count_ones.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write a function that takes an unsigned integer and 3 | returns the number of ’1' bits it has 4 | (also known as the Hamming weight). 5 | 6 | For example, the 32-bit integer ’11' has binary 7 | representation 00000000000000000000000000001011, 8 | so the function should return 3. 9 | """ 10 | 11 | 12 | def count_ones(n): 13 | """ 14 | :type n: int 15 | :rtype: int 16 | """ 17 | counter = 0 18 | while n: 19 | counter += n & 1 20 | n >>= 1 21 | return counter 22 | -------------------------------------------------------------------------------- /bit/power_of_two.py: -------------------------------------------------------------------------------- 1 | """ 2 | given an integer, write a function to determine if it is a power of two 3 | """ 4 | 5 | 6 | def is_power_of_two(n): 7 | """ 8 | :type n: int 9 | :rtype: bool 10 | """ 11 | return n > 0 and not n & (n-1) 12 | -------------------------------------------------------------------------------- /bit/reverse_bits.py: -------------------------------------------------------------------------------- 1 | """ 2 | Reverse bits of a given 32 bits unsigned integer. 3 | 4 | For example, given input 43261596 5 | (represented in binary as 00000010100101000001111010011100), 6 | return 964176192 7 | (represented in binary as 00111001011110000010100101000000). 8 | """ 9 | 10 | 11 | def reverse_bits(n): 12 | m = 0 13 | i = 0 14 | while i < 32: 15 | m = (m << 1) + (n & 1) 16 | n >>= 1 17 | i += 1 18 | return m 19 | -------------------------------------------------------------------------------- /bit/single_number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers, every element appears 3 | twice except for one. Find that single one. 4 | 5 | Note: 6 | Your algorithm should have a linear runtime complexity. 7 | Could you implement it without using extra memory? 8 | """ 9 | 10 | 11 | def single_number(nums): 12 | """ 13 | :type nums: List[int] 14 | :rtype: int 15 | """ 16 | i = 0 17 | for num in nums: 18 | i ^= num 19 | return i 20 | -------------------------------------------------------------------------------- /bit/single_number2.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers, every element appears 3 | three times except for one, which appears exactly once. 4 | Find that single one. 5 | 6 | Note: 7 | Your algorithm should have a linear runtime complexity. 8 | Could you implement it without using extra memory? 9 | """ 10 | 11 | 12 | """ 13 | 32 bits for each integer. 14 | Consider 1 bit in it, the sum of each integer's corresponding bit 15 | (except for the single number) 16 | should be 0 if mod by 3. Hence, we sum the bits of all 17 | integers and mod by 3, 18 | the remaining should be the exact bit of the single number. 19 | In this way, you get the 32 bits of the single number. 20 | """ 21 | 22 | 23 | def single_number(nums): 24 | """ 25 | :type nums: List[int] 26 | :rtype: int 27 | """ 28 | res = 0 29 | for i in range(0, 32): 30 | count = 0 31 | for num in nums: 32 | if ((num >> i) & 1): 33 | count += 1 34 | res |= ((count % 3) << i) 35 | if res >= 2**31: 36 | res -= 2**32 37 | return res 38 | 39 | 40 | # Another awesome answer 41 | def single_number2(nums): 42 | ones, twos = 0, 0 43 | for i in range(len(nums)): 44 | ones = (ones ^ nums[i]) & ~twos 45 | twos = (twos ^ nums[i]) & ~ones 46 | return ones 47 | -------------------------------------------------------------------------------- /bit/subsets.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a set of distinct integers, nums, 3 | return all possible subsets. 4 | 5 | Note: The solution set must not contain duplicate subsets. 6 | 7 | For example, 8 | If nums = [1,2,3], a solution is: 9 | 10 | [ 11 | [3], 12 | [1], 13 | [2], 14 | [1,2,3], 15 | [1,3], 16 | [2,3], 17 | [1,2], 18 | [] 19 | ] 20 | """ 21 | 22 | 23 | def subnets(nums): 24 | nums.sort() 25 | total = 2 ** len(nums) # or 1 << len(nums) 26 | res = [] * total 27 | 28 | for i in range(total): 29 | res.append([]) 30 | 31 | for i in range(len(nums)): 32 | for j in range(total): 33 | if ((j >> i) & 1) > 0: # i & 1 << j 34 | res[j].append(nums[i]) 35 | return res 36 | 37 | 38 | def subsets2(self, nums): 39 | res = [] 40 | nums.sort() 41 | for i in range(1 << len(nums)): 42 | tmp = [] 43 | for j in range(len(nums)): 44 | if i & 1 << j: # if i >> j & 1: 45 | tmp.append(nums[j]) 46 | res.append(tmp) 47 | return res 48 | 49 | """ 50 | this explanation is from leet_nik @ leetcode 51 | This is an amazing solution. Learnt a lot. 52 | 53 | Number of subsets for {1 , 2 , 3 } = 2^3 . 54 | why ? 55 | case possible outcomes for the set of subsets 56 | 1 -> Take or dont take = 2 57 | 2 -> Take or dont take = 2 58 | 3 -> Take or dont take = 2 59 | 60 | therefore, 61 | total = 2*2*2 = 2^3 = {{}, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}} 62 | 63 | Lets assign bits to each outcome -> 64 | First bit to 1 , Second bit to 2 and third bit to 3 65 | Take = 1 66 | Dont take = 0 67 | 68 | 0) 0 0 0 -> Dont take 3 , Dont take 2 , Dont take 1 = { } 69 | 1) 0 0 1 -> Dont take 3 , Dont take 2 , take 1 = { 1 } 70 | 2) 0 1 0 -> Dont take 3 , take 2 , Dont take 1 = { 2 } 71 | 3) 0 1 1 -> Dont take 3 , take 2 , take 1 = { 1 , 2 } 72 | 4) 1 0 0 -> take 3 , Dont take 2 , Dont take 1 = { 3 } 73 | 5) 1 0 1 -> take 3 , Dont take 2 , take 1 = { 1 , 3 } 74 | 6) 1 1 0 -> take 3 , take 2 , Dont take 1 = { 2 , 3 } 75 | 7) 1 1 1 -> take 3 , take 2 , take 1 = { 1 , 2 , 3 } 76 | 77 | In the above logic ,Insert S[i] only if (j>>i)&1 ==true 78 | { j E { 0,1,2,3,4,5,6,7 } i = ith element in the input array } 79 | 80 | element 1 is inserted only into those places where 1st bit of j is 1 81 | if( j >> 0 &1 ) ==> for above above eg. 82 | this is true for sl.no.( j )= 1 , 3 , 5 , 7 83 | 84 | element 2 is inserted only into those places where 2nd bit of j is 1 85 | if( j >> 1 &1 ) == for above above eg. 86 | this is true for sl.no.( j ) = 2 , 3 , 6 , 7 87 | 88 | element 3 is inserted only into those places where 3rd bit of j is 1 89 | if( j >> 2 & 1 ) == for above above eg. 90 | this is true for sl.no.( j ) = 4 , 5 , 6 , 7 91 | 92 | Time complexity : O(n*2^n) , for every input element loop traverses 93 | the whole solution set length i.e. 2^n 94 | """ 95 | -------------------------------------------------------------------------------- /design/LRUcache.md: -------------------------------------------------------------------------------- 1 | Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put. 2 | 3 | get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. 4 | put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item. 5 | 6 | Follow up: 7 | Could you do both operations in O(1) time complexity? 8 | 9 | Example: 10 | ``` 11 | LRUCache cache = new LRUCache( 2 /* capacity */ ); 12 | 13 | cache.put(1, 1); 14 | cache.put(2, 2); 15 | cache.get(1); // returns 1 16 | cache.put(3, 3); // evicts key 2 17 | cache.get(2); // returns -1 (not found) 18 | cache.put(4, 4); // evicts key 1 19 | cache.get(1); // returns -1 (not found) 20 | cache.get(3); // returns 3 21 | cache.get(4); // returns 4 22 | ``` 23 | 24 | ```python 25 | class Node: 26 | def __init__(self, k, v): 27 | self.key = k 28 | self.val = v 29 | self.prev = None 30 | self.next = None 31 | 32 | class LRUCache: 33 | def __init__(self, capacity): 34 | self.capacity = capacity 35 | self.dic = dict() 36 | self.head = Node(0, 0) 37 | self.tail = Node(0, 0) 38 | self.head.next = self.tail 39 | self.tail.prev = self.head 40 | 41 | def get(self, key): 42 | if key in self.dic: 43 | n = self.dic[key] 44 | self._remove(n) 45 | self._add(n) 46 | return n.val 47 | return -1 48 | 49 | def set(self, key, value): 50 | if key in self.dic: 51 | self._remove(self.dic[key]) 52 | n = Node(key, value) 53 | self._add(n) 54 | self.dic[key] = n 55 | if len(self.dic) > self.capacity: 56 | n = self.head.next 57 | self._remove(n) 58 | del self.dic[n.key] 59 | 60 | def _remove(self, node): 61 | p = node.prev 62 | n = node.next 63 | p.next = n 64 | n.prev = p 65 | 66 | def _add(self, node): 67 | p = self.tail.prev 68 | p.next = node 69 | self.tail.prev = node 70 | node.prev = p 71 | node.next = self.tail 72 | ``` 73 | 74 | Little Easier to read with comments 75 | 76 | ```python 77 | class LRUCache(object): 78 | 79 | def __init__(self, capacity): 80 | self.capacity = capacity 81 | self.head = LinkedNode(None,'head') 82 | self.tail = LinkedNode(None,'tail') 83 | self.head.next = self.tail # tail being most recent 84 | self.tail.prev = self.head # head being oldest 85 | self.data = {} 86 | 87 | def deleteNode(self,node): 88 | assert(node is not self.head and node is not self.tail) 89 | del self.data[node.key] 90 | node.prev.next = node.next 91 | node.next.prev = node.prev 92 | del node 93 | 94 | def get(self,key): 95 | if key not in self.data: 96 | return -1 97 | node = self.data[key] 98 | # take the node out 99 | node.prev.next = node.next 100 | node.next.prev = node.prev 101 | # insert into most recent position 102 | self.insertNew(node) 103 | return node.value 104 | 105 | def put(self, key, value): 106 | # remove old value if present 107 | if key in self.data: 108 | self.deleteNode(self.data[key]) 109 | 110 | # create new node 111 | newNode = LinkedNode(key,value) 112 | self.data[key] = newNode 113 | 114 | # if over limit, delete oldest node 115 | if len(self.data)>self.capacity: 116 | self.deleteNode(self.head.next) 117 | 118 | self.insertNew(newNode) 119 | 120 | def insertNew(self,newNode): 121 | # insert new node into last position 122 | last = self.tail.prev 123 | last.next = newNode 124 | self.tail.prev = newNode 125 | newNode.next = self.tail 126 | newNode.prev = last 127 | ``` 128 | -------------------------------------------------------------------------------- /design/alarm_system.md: -------------------------------------------------------------------------------- 1 | Design an alarm system for a driverless car 2 | -------------------------------------------------------------------------------- /design/calculator.md: -------------------------------------------------------------------------------- 1 | ## Q 2 | Implement a basic calculator, supporting operators such as +, -, *, / and operands like ( and ). 3 | 4 | For example: 5 | `"(1+2) *10 -25/(1-7)" -> 34` 6 | 7 | ## A 8 | I think that maybe there is an error in the example above. The expression should be : (1+2)*10-24/(1-7) -> 34 9 | Here is some implementation, convert infix notation in reverse pollish notation and calculate it 10 | ``` 11 | boolean isDigit(char ch) { 12 | return ch >= '0' && ch <= '9'; 13 | } 14 | int calc(int op2, int op1, char ch) { 15 | switch(ch) { 16 | case '-': return op1 - op2; 17 | case '+': return op1 + op2; 18 | case '/': return op1 / op2; 19 | case '*': return op1 * op2; 20 | } 21 | return 0; 22 | } 23 | boolean higherPriority(char op1, char op2) { 24 | if ((op1 =='*') || (op1 =='/')) 25 | return true; 26 | if ((op2 =='+') || (op2 =='-')) 27 | return true; 28 | return false; 29 | } 30 | int simpleCalculator(String exp) { 31 | Stack st = new Stack<>(); 32 | Stack op = new Stack<>(); 33 | int digit = 0; 34 | boolean hasDigit = false; 35 | for (int i = 0; i < exp.length(); i++) { 36 | if (isDigit(exp.charAt(i))) { 37 | hasDigit = true; 38 | digit = digit*10 + (exp.charAt(i) - '0'); 39 | } else { 40 | if(hasDigit) { 41 | hasDigit = false; 42 | st.push(digit); 43 | digit = 0; 44 | } 45 | if (exp.charAt(i) == '(') { 46 | op.push('('); 47 | } else if(exp.charAt(i) == ')') { 48 | while (op.peek() != '(') { 49 | st.push(calc(st.pop(), st.pop(), op.pop())); 50 | } 51 | op.pop(); 52 | } else { 53 | while (!op.isEmpty() && op.peek() != '(' && higherPriority(op.peek(), exp.charAt(i))) { 54 | st.push(calc(st.pop(), st.pop(), op.pop())); 55 | } 56 | op.push(exp.charAt(i)); 57 | } 58 | } 59 | } 60 | if(hasDigit) 61 | st.push(digit); 62 | while(!op.isEmpty()) { 63 | st.push(calc(st.pop(), st.pop(), op.pop())); 64 | } 65 | return st.peek(); 66 | } 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /design/excel_table.md: -------------------------------------------------------------------------------- 1 | ## Q 2 | 3 | Need to implement set and get operations. 4 | Be aware that one cell may depend on other cells, 5 | e.g. cells[1, 2] = cells[1, 1] + cell[1, 3] * 2 6 | 7 | ## A 8 | 9 | Could you give more details in the description and an example? 10 | 11 | For example, it is not clear how the inputs are given. 12 | How is the spreadsheet represented? A 2d array of cells? Each cell contains a string? 13 | 14 | Input: 15 | ``` 16 | [ 17 | ["100", "A2*3"], 18 | ["B2+A1", "200"] 19 | ] 20 | 21 | ``` 22 | Output: 23 | ``` 24 | [ 25 | ["100", "900"], 26 | ["300", "200"] 27 | ] 28 | ``` 29 | Is it like the above? And what about circular reference? What should the output be? 30 | -------------------------------------------------------------------------------- /design/nearby_drivers.md: -------------------------------------------------------------------------------- 1 | Design the backend architecture to show nearby drivers 2 | -------------------------------------------------------------------------------- /design/ride_sharing.md: -------------------------------------------------------------------------------- 1 | Consider that the driver with one trip want to pick up some peoples in different locations like this: 2 | String[] locations ={ 3 | "person1, person2, person3, person4, person5", 4 | " person6, person7, person8, person9", 5 | "person10, person11, person12", 6 | "person13, person14, person15",} 7 | in each location there are different choice, so write a code present all possible way to pick up people in the different locations. 8 | you can use every data structure needs. 9 | 10 | 11 | This could be solved using minimum spanning tree concept 12 | 13 | ***assume taxi is large enough for all passengers**** 14 | 15 | Arrange all the pickup locations as vertices of a graph along with the present location of the taxi as 16 | 17 | one of the vertex 18 | 19 | now start with the present location and add that edge with has lowest weight ,this means we have 20 | 21 | visited to the location which is nearby and pic all the passangers, then search for the next nearby location 22 | 23 | locations and so on until all the locations are visited once 24 | -------------------------------------------------------------------------------- /design/task_runner.md: -------------------------------------------------------------------------------- 1 | ## Q 2 | Implement Task Runner. 3 | 4 | TaskRunner takes concurrency as it's input. 5 | 'concurrency' is the number of the tasks that the TaskRunner 6 | can simultaneously execute. Keep pushing the tasks until the 7 | concurrency is reached. Once the limit is reached, 8 | wait for one of the tasks to be completed and then, execute other tasks. 9 | 10 | ## A 11 | 12 | ``` 13 | 'use strict'; 14 | function exampleTask(done) { 15 | setTimeout(done, 2000); 16 | } 17 | 18 | class Runner { 19 | constructor(num){ 20 | this.maxNum = num; 21 | this.counter = 0; 22 | this.queue = []; 23 | } 24 | 25 | push(callbackFn){ 26 | this.queue.push(callbackFn); 27 | } 28 | 29 | run(){ 30 | var self = this; 31 | if(this.queue.length > 0 && this.counter < this.maxNum){ 32 | setTimeout(() => { 33 | this.counter++; 34 | let task = this.queue.shift(); 35 | var done = function(){ 36 | self.counter--; 37 | console.log(`number at this moment:${self.counter}`) 38 | self.run(); 39 | } 40 | task.call(this,done); 41 | },0); 42 | } 43 | } 44 | } 45 | 46 | var r = new Runner(3); 47 | r.push(exampleTask) // run 48 | r.push(exampleTask) // run 49 | r.push(exampleTask) // run 50 | r.push(exampleTask) // wait 51 | r.run(); 52 | ``` 53 | -------------------------------------------------------------------------------- /design/twitter_feeds.md: -------------------------------------------------------------------------------- 1 | Design a Twitter feeds API. 2 | How would you actually connect it from a mobile? 3 | What happens behind the Twitter network? 4 | how do the Trends get published? 5 | From where does Twitter get the information for a particular trend(Eg: #Obama, #nfl) 6 | and publish it out? 7 | What protocol does it use? 8 | How do you connect to Twitter API? 9 | How does Twitter handle multiple connections? 10 | 11 | 12 | 13 | Twitter feeds API for 1 user: 14 | The user has M friends and each friend has K new updates. 15 | One possible way is to iterate over all friends and get all the new updates 16 | and display that in feed. O(MK). 17 | But iterating over all the friends is a costly operation, 18 | so i should be getting the feeds from those people whose pics and feeds 19 | i like or comment on or share. We have reduced the iteration on number of people. 20 | We can also use collaborative filtering to decide - what kind of feeds i 21 | would be interested in. Instead of doing all the computations on the fly, 22 | some things can be done offline - for example, 23 | store latest feeds from my friends after I was last active and when i come online, 24 | show those in chronological order. 25 | 26 | Connect to Twitter API: Whenever a person gives her credentials 27 | that means one connection is awarded to her. 28 | Now if multiple connections are opened for the same user then according to 29 | 'last used' parameter certain connections can be closed. 30 | Also if the user exceeds the limit of number of connections allowed then old connections should be closed. 31 | 32 | Twitter uses streaming API. I am not sure about twitter trends though. Can someone elaborate on that? 33 | -------------------------------------------------------------------------------- /dfs/all_factors.py: -------------------------------------------------------------------------------- 1 | """ 2 | Numbers can be regarded as product of its factors. For example, 3 | 8 = 2 x 2 x 2; 4 | = 2 x 4. 5 | 6 | 7 | Write a function that takes an integer n and return all possible combinations 8 | of its factors.Numbers can be regarded as product of its factors. For example, 9 | 8 = 2 x 2 x 2; 10 | = 2 x 4. 11 | 12 | Examples: 13 | input: 1 14 | output: 15 | [] 16 | 17 | 18 | input: 37 19 | output: 20 | [] 21 | 22 | input: 32 23 | output: 24 | [ 25 | [2, 16], 26 | [2, 2, 8], 27 | [2, 2, 2, 4], 28 | [2, 2, 2, 2, 2], 29 | """ 30 | 31 | 32 | def get_factors(n): 33 | def factor(n, i, combi, res): 34 | while i * i <= n: 35 | if n % i == 0: 36 | res += combi + [i, int(n/i)], 37 | factor(n/i, i, combi+[i], res) 38 | i += 1 39 | return res 40 | return factor(n, 2, [], []) 41 | 42 | 43 | def get_factors_iterative1(self, n): 44 | todo, res = [(n, 2, [])], [] 45 | while todo: 46 | n, i, combi = todo.pop() 47 | while i * i <= n: 48 | if n % i == 0: 49 | res += combi + [i, n/i], 50 | todo += (n/i, i, combi+[i]), 51 | i += 1 52 | return res 53 | 54 | 55 | def get_factors_iterative2(n): 56 | ans, stack, x = [], [], 2 57 | while True: 58 | if x > n / x: 59 | if not stack: 60 | return ans 61 | ans.append(stack + [n]) 62 | x = stack.pop() 63 | n *= x 64 | x += 1 65 | elif n % x == 0: 66 | stack.append(x) 67 | n /= x 68 | else: 69 | x += 1 70 | 71 | 72 | if __name__ == "__main__": 73 | print(get_factors(32)) 74 | -------------------------------------------------------------------------------- /dfs/count_islands.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a 2d grid map of '1's (land) and '0's (water), 3 | count the number of islands. 4 | An island is surrounded by water and is formed by 5 | connecting adjacent lands horizontally or vertically. 6 | You may assume all four edges of the grid are all surrounded by water. 7 | 8 | Example 1: 9 | 10 | 11110 11 | 11010 12 | 11000 13 | 00000 14 | Answer: 1 15 | 16 | Example 2: 17 | 18 | 11000 19 | 11000 20 | 00100 21 | 00011 22 | Answer: 3 23 | """ 24 | 25 | def num_islands(grid): 26 | count = 0 27 | for i, row in enumerate(grid): 28 | for j, col in enumerate(grid[i]): 29 | if col == '1': 30 | DFS(grid, i, j) 31 | count += 1 32 | return count 33 | 34 | 35 | def DFS(grid, i, j): 36 | if (i < 0 or i >= len(grid)) or (j < 0 or len(grid[0])): 37 | return 38 | if grid[i][j] != '1': 39 | return 40 | grid[i][j] = '0' 41 | DFS(grid, i+1, j) 42 | DFS(grid, i-1, j) 43 | DFS(grid, i, j+1) 44 | DFS(grid, i, j-1) 45 | -------------------------------------------------------------------------------- /dfs/pacific_atlantic.py: -------------------------------------------------------------------------------- 1 | # Given an m x n matrix of non-negative integers representing 2 | # the height of each unit cell in a continent, 3 | # the "Pacific ocean" touches the left and top edges of the matrix 4 | # and the "Atlantic ocean" touches the right and bottom edges. 5 | 6 | # Water can only flow in four directions (up, down, left, or right) 7 | # from a cell to another one with height equal or lower. 8 | 9 | # Find the list of grid coordinates where water can flow to both the 10 | # Pacific and Atlantic ocean. 11 | 12 | # Note: 13 | # The order of returned grid coordinates does not matter. 14 | # Both m and n are less than 150. 15 | # Example: 16 | 17 | # Given the following 5x5 matrix: 18 | 19 | # Pacific ~ ~ ~ ~ ~ 20 | # ~ 1 2 2 3 (5) * 21 | # ~ 3 2 3 (4) (4) * 22 | # ~ 2 4 (5) 3 1 * 23 | # ~ (6) (7) 1 4 5 * 24 | # ~ (5) 1 1 2 4 * 25 | # * * * * * Atlantic 26 | 27 | # Return: 28 | 29 | # [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] 30 | # (positions with parentheses in above matrix). 31 | 32 | def pacific_atlantic(matrix): 33 | """ 34 | :type matrix: List[List[int]] 35 | :rtype: List[List[int]] 36 | """ 37 | n = len(matrix) 38 | if not n: return [] 39 | m = len(matrix[0]) 40 | if not m: return [] 41 | res = [] 42 | atlantic = [[False for _ in range (n)] for _ in range(m)] 43 | pacific = [[False for _ in range (n)] for _ in range(m)] 44 | for i in range(n): 45 | DFS(pacific, matrix, float("-inf"), i, 0) 46 | DFS(atlantic, matrix, float("-inf"), i, m-1) 47 | for i in range(m): 48 | DFS(pacific, matrix, float("-inf"), 0, i) 49 | DFS(atlantic, matrix, float("-inf"), n-1, i) 50 | for i in range(n): 51 | for j in range(m): 52 | if pacific[i][j] and atlantic[i][j]: 53 | res.append([i, j]) 54 | return res 55 | 56 | def DFS(grid, matrix, height, i, j): 57 | if i < 0 or i >= len(matrix) or j < 0 or j >= len(matrix[0]): 58 | return 59 | if grid[i][j] or matrix[i][j] < height: 60 | return 61 | grid[i][j] = True 62 | DFS(grid, matrix, matrix[i][j], i-1, j) 63 | DFS(grid, matrix, matrix[i][j], i+1, j) 64 | DFS(grid, matrix, matrix[i][j], i, j-1) 65 | DFS(grid, matrix, matrix[i][j], i, j+1) 66 | -------------------------------------------------------------------------------- /dfs/sudoku_solver.py: -------------------------------------------------------------------------------- 1 | """ 2 | It's similar to how human solve Sudoku. 3 | 4 | create a hash table (dictionary) val to store possible values in every location. 5 | Each time, start from the location with fewest possible values, choose one value 6 | from it and then update the board and possible values at other locations. 7 | If this update is valid, keep solving (DFS). If this update is invalid (leaving 8 | zero possible values at some locations) or this value doesn't lead to the 9 | solution, undo the updates and then choose the next value. 10 | Since we calculated val at the beginning and start filling the board from the 11 | location with fewest possible values, the amount of calculation and thus the 12 | runtime can be significantly reduced: 13 | 14 | 15 | The run time is 48-68 ms on LeetCode OJ, which seems to be among the fastest 16 | python solutions here. 17 | 18 | 19 | The PossibleVals function may be further simplified/optimized, but it works just 20 | fine for now. (it would look less lengthy if we are allowed to use numpy array 21 | for the board lol). 22 | """ 23 | 24 | def solveSudoku(self, board): 25 | self.board = board 26 | self.val = self.PossibleVals() 27 | self.Solver() 28 | 29 | def PossibleVals(self): 30 | a = "123456789" 31 | d, val = {}, {} 32 | for i in xrange(9): 33 | for j in xrange(9): 34 | ele = self.board[i][j] 35 | if ele != ".": 36 | d[("r", i)] = d.get(("r", i), []) + [ele] 37 | d[("c", j)] = d.get(("c", j), []) + [ele] 38 | d[(i//3, j//3)] = d.get((i//3, j//3), []) + [ele] 39 | else: 40 | val[(i,j)] = [] 41 | for (i,j) in val.keys(): 42 | inval = d.get(("r",i),[])+d.get(("c",j),[])+d.get((i/3,j/3),[]) 43 | val[(i,j)] = [n for n in a if n not in inval ] 44 | return val 45 | 46 | def Solver(self): 47 | if len(self.val)==0: 48 | return True 49 | kee = min(self.val.keys(), key=lambda x: len(self.val[x])) 50 | nums = self.val[kee] 51 | for n in nums: 52 | update = {kee:self.val[kee]} 53 | if self.ValidOne(n, kee, update): # valid choice 54 | if self.Solver(): # keep solving 55 | return True 56 | self.undo(kee, update) # invalid choice or didn't solve it => undo 57 | return False 58 | 59 | def ValidOne(self, n, kee, update): 60 | self.board[kee[0]][kee[1]] = n 61 | del self.val[kee] 62 | i, j = kee 63 | for ind in self.val.keys(): 64 | if n in self.val[ind]: 65 | if ind[0]==i or ind[1]==j or (ind[0]/3,ind[1]/3)==(i/3,j/3): 66 | update[ind] = n 67 | self.val[ind].remove(n) 68 | if len(self.val[ind])==0: 69 | return False 70 | return True 71 | 72 | def undo(self, kee, update): 73 | self.board[kee[0]][kee[1]]="." 74 | for k in update: 75 | if k not in self.val: 76 | self.val[k]= update[k] 77 | else: 78 | self.val[k].append(update[k]) 79 | return None 80 | -------------------------------------------------------------------------------- /dfs/walls_and_gates.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # fill the empty room with distance to its nearest gate 4 | 5 | 6 | def walls_and_gates(rooms): 7 | for i in range(len(rooms)): 8 | for j in range(len(rooms[0])): 9 | if rooms[i][j] == 0: 10 | DFS(rooms, i, j, 0) 11 | 12 | 13 | def DFS(rooms, i, j, depth): 14 | if (i < 0 or i >= len(rooms)) or (j < 0 or j >= len(rooms[0])): 15 | return # out of bounds 16 | if rooms[i][j] < depth: 17 | return # crossed 18 | rooms[i][j] = depth 19 | DFS(rooms, i+1, j, depth+1) 20 | DFS(rooms, i-1, j, depth+1) 21 | DFS(rooms, i, j+1, depth+1) 22 | DFS(rooms, i, j-1, depth+1) 23 | -------------------------------------------------------------------------------- /dp/buy_sell_stock.py: -------------------------------------------------------------------------------- 1 | """ 2 | Say you have an array for which the ith element 3 | is the price of a given stock on day i. 4 | 5 | If you were only permitted to complete at most one transaction 6 | (ie, buy one and sell one share of the stock), 7 | design an algorithm to find the maximum profit. 8 | 9 | Example 1: 10 | Input: [7, 1, 5, 3, 6, 4] 11 | Output: 5 12 | 13 | max. difference = 6-1 = 5 14 | (not 7-1 = 6, as selling price needs to be larger than buying price) 15 | Example 2: 16 | Input: [7, 6, 4, 3, 1] 17 | Output: 0 18 | 19 | In this case, no transaction is done, i.e. max profit = 0. 20 | """ 21 | 22 | 23 | def max_profit(prices): 24 | """ 25 | input: [7, 1, 5, 3, 6, 4] 26 | diff : [X,-6, 5,-2, 3,-2] 27 | :type prices: List[int] 28 | :rtype: int 29 | """ 30 | cur_max, max_so_far = 0, 0 31 | for i in range(1, len(prices)): 32 | cur_max = max(0, cur_max + prices[i] - prices[i-1]) 33 | max_so_far = max(max_so_far, cur_max) 34 | return max_so_far 35 | -------------------------------------------------------------------------------- /dp/climbing_stairs.py: -------------------------------------------------------------------------------- 1 | """ 2 | You are climbing a stair case. 3 | It takes n steps to reach to the top. 4 | 5 | Each time you can either climb 1 or 2 steps. 6 | In how many distinct ways can you climb to the top? 7 | 8 | Note: Given n will be a positive integer. 9 | """ 10 | 11 | 12 | # O(n) space 13 | 14 | def climb_stairs(n): 15 | """ 16 | :type n: int 17 | :rtype: int 18 | """ 19 | arr = [1, 1] 20 | for i in range(2, n+1): 21 | arr.append(arr[-1] + arr[-2]) 22 | return arr[-1] 23 | 24 | 25 | # the above function can be optimized as: 26 | # O(1) space 27 | 28 | def climb_stairs_optimized(n): 29 | a = b = 1 30 | for _ in range(n): 31 | a, b = b, a + b 32 | return a 33 | -------------------------------------------------------------------------------- /dp/combination_sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array with all positive numbers and no duplicates, 3 | find the number of possible combinations that 4 | add up to a positive integer target. 5 | 6 | Example: 7 | 8 | nums = [1, 2, 3] 9 | target = 4 10 | 11 | The possible combination ways are: 12 | (1, 1, 1, 1) 13 | (1, 1, 2) 14 | (1, 2, 1) 15 | (1, 3) 16 | (2, 1, 1) 17 | (2, 2) 18 | (3, 1) 19 | 20 | Note that different sequences are counted as different combinations. 21 | 22 | Therefore the output is 7. 23 | Follow up: 24 | What if negative numbers are allowed in the given array? 25 | How does it change the problem? 26 | What limitation we need to add to the question to allow negative numbers? 27 | 28 | """ 29 | 30 | dp = None 31 | 32 | 33 | def helper_topdown(nums, target): 34 | global dp 35 | if dp[target] != -1: 36 | return dp[target] 37 | res = 0 38 | for i in range(0, len(nums)): 39 | if target >= nums[i]: 40 | res += helper_topdown(nums, target - nums[i]) 41 | dp[target] = res 42 | return res 43 | 44 | 45 | def combination_sum_topdown(nums, target): 46 | global dp 47 | dp = [-1] * (target + 1) 48 | dp[0] = 1 49 | return helper_topdown(nums, target) 50 | 51 | 52 | # EDIT: The above solution is top-down. How about a bottom-up one? 53 | def combination_sum_bottom_up(nums, target): 54 | comb = [0] * (target + 1) 55 | comb[0] = 1 56 | for i in range(0, len(comb)): 57 | for j in range(len(nums)): 58 | if i - nums[j] >= 0: 59 | comb[i] += comb[i - nums[j]] 60 | return comb[target] 61 | 62 | 63 | combination_sum_topdown([1, 2, 3], 4) 64 | print dp[4] 65 | 66 | print combination_sum_bottom_up([1, 2, 3], 4) 67 | -------------------------------------------------------------------------------- /dp/house_robber.py: -------------------------------------------------------------------------------- 1 | """ 2 | You are a professional robber planning to rob houses along a street. 3 | Each house has a certain amount of money stashed, 4 | the only constraint stopping you from robbing each of them 5 | is that adjacent houses have security system connected and 6 | it will automatically contact the police if two adjacent houses 7 | were broken into on the same night. 8 | 9 | Given a list of non-negative integers representing the amount of money 10 | of each house, determine the maximum amount of money you 11 | can rob tonight without alerting the police. 12 | """ 13 | 14 | 15 | def house_robber(houses): 16 | last, now = 0, 0 17 | for house in houses: 18 | tmp = now 19 | now = max(last + house, now) 20 | last = tmp 21 | return now 22 | 23 | houses = [1, 2, 16, 3, 15, 3, 12, 1] 24 | 25 | print(house_robber(houses)) 26 | -------------------------------------------------------------------------------- /dp/longest_increasing.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def longest_increasing_subsequence(sequence): 4 | """ 5 | Dynamic Programming Algorithm for 6 | counting the length of longest increasing subsequence 7 | type sequence: List[int] 8 | """ 9 | length = len(sequence) 10 | counts = [1 for _ in range(length)] 11 | for i in range(1, length): 12 | for j in range(0, i): 13 | if sequence[i] > sequence[j]: 14 | counts[i] = max(counts[i], counts[j] + 1) 15 | print(counts) 16 | return max(counts) 17 | 18 | 19 | sequence = [1, 101, 10, 2, 3, 100, 4, 6, 2] 20 | print("sequence: ", sequence) 21 | print("output: ", longest_increasing_subsequence(sequence)) 22 | print("answer: ", 5) 23 | 24 | -------------------------------------------------------------------------------- /dp/max_product_subarray.py: -------------------------------------------------------------------------------- 1 | """ 2 | Find the contiguous subarray within an array 3 | (containing at least one number) which has the largest product. 4 | 5 | For example, given the array [2,3,-2,4], 6 | the contiguous subarray [2,3] has the largest product = 6. 7 | """ 8 | 9 | 10 | def max_product(nums): 11 | """ 12 | :type nums: List[int] 13 | :rtype: int 14 | """ 15 | lmin = lmax = gmax = nums[0] 16 | for i in range(len(nums)): 17 | t1 = nums[i] * lmax 18 | t2 = nums[i] * lmin 19 | lmax = max(max(t1, t2), nums[i]) 20 | lmin = min(min(t1, t2), nums[i]) 21 | gmax = max(gmax, lmax) 22 | -------------------------------------------------------------------------------- /dp/max_subarray.py: -------------------------------------------------------------------------------- 1 | 2 | def max_subarray(array): 3 | max_so_far = max_now = array[0] 4 | for i in range(1, len(array)): 5 | max_now = max(array[i], max_now + array[i]) 6 | max_so_far = max(max_so_far, max_now) 7 | return max_so_far 8 | 9 | a = [1, 2, -3, 4, 5, -7, 23] 10 | print(a) 11 | print(max_subarray(a)) 12 | -------------------------------------------------------------------------------- /dp/num_decodings.py: -------------------------------------------------------------------------------- 1 | """ 2 | A message containing letters from A-Z is being 3 | encoded to numbers using the following mapping: 4 | 5 | 'A' -> 1 6 | 'B' -> 2 7 | ... 8 | 'Z' -> 26 9 | Given an encoded message containing digits, 10 | determine the total number of ways to decode it. 11 | 12 | For example, 13 | Given encoded message "12", 14 | it could be decoded as "AB" (1 2) or "L" (12). 15 | 16 | The number of ways decoding "12" is 2. 17 | """ 18 | 19 | 20 | def num_decodings(s): 21 | """ 22 | :type s: str 23 | :rtype: int 24 | """ 25 | if not s or s[0] == "0": 26 | return 0 27 | wo_last, wo_last_two = 1, 1 28 | for i in range(1, len(s)): 29 | x = wo_last if s[i] != "0" else 0 30 | y = wo_last_two if int(s[i-1:i+1]) < 27 and s[i-1] != "0" else 0 31 | wo_last_two = wo_last 32 | wo_last = x+y 33 | return wo_last 34 | 35 | 36 | def num_decodings2(s): 37 | if not s or s.startswith('0'): 38 | return 0 39 | stack = [1, 1] 40 | for i in range(1, len(s)): 41 | if s[i] == '0': 42 | if s[i-1] == '0' or s[i-1] > '2': 43 | # only '10', '20' is valid 44 | return 0 45 | stack.append(stack[-2]) 46 | elif 9 < int(s[i-1:i+1]) < 27: 47 | # '01 - 09' is not allowed 48 | stack.append(stack[-2]+stack[-1]) 49 | else: 50 | # other case '01, 09, 27' 51 | stack.append(stack[-1]) 52 | return stack[-1] 53 | -------------------------------------------------------------------------------- /dp/regex_matching.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement regular expression matching with support for '.' and '*'. 3 | 4 | '.' Matches any single character. 5 | '*' Matches zero or more of the preceding element. 6 | 7 | The matching should cover the entire input string (not partial). 8 | 9 | The function prototype should be: 10 | bool isMatch(const char *s, const char *p) 11 | 12 | Some examples: 13 | isMatch("aa","a") → false 14 | isMatch("aa","aa") → true 15 | isMatch("aaa","aa") → false 16 | isMatch("aa", "a*") → true 17 | isMatch("aa", ".*") → true 18 | isMatch("ab", ".*") → true 19 | isMatch("aab", "c*a*b") → true 20 | """ 21 | 22 | class Solution(object): 23 | def isMatch(self, s, p): 24 | m, n = len(s) + 1, len(p) + 1 25 | matches = [[False] * n for _ in range(m)] 26 | 27 | # Match empty string with empty pattern 28 | matches[0][0] = True 29 | 30 | # Match empty string with .* 31 | for i, element in enumerate(p[1:], 2): 32 | matches[0][i] = matches[0][i - 2] and element == '*' 33 | 34 | for i, ss in enumerate(s, 1): 35 | for j, pp in enumerate(p, 1): 36 | if pp != '*': 37 | # The previous character has matched and the current one 38 | # has to be matched. Two possible matches: the same or . 39 | matches[i][j] = matches[i - 1][j - 1] and \ 40 | (ss == pp or pp == '.') 41 | else: 42 | # Horizontal look up [j - 2]. 43 | # Not use the character before *. 44 | matches[i][j] |= matches[i][j - 2] 45 | 46 | # Vertical look up [i - 1]. 47 | # Use at least one character before *. 48 | # p a b * 49 | # s 1 0 0 0 50 | # a 0 1 0 1 51 | # b 0 0 1 1 52 | # b 0 0 0 ? 53 | if ss == p[j - 2] or p[j - 2] == '.': 54 | matches[i][j] |= matches[i - 1][j] 55 | 56 | return matches[-1][-1] 57 | 58 | class TestSolution(unittest.TestCase): 59 | def test_none_0(self): 60 | s = "" 61 | p = "" 62 | self.assertTrue(Solution().isMatch(s, p)) 63 | 64 | def test_none_1(self): 65 | s = "" 66 | p = "a" 67 | self.assertFalse(Solution().isMatch(s, p)) 68 | 69 | def test_no_symbol_equal(self): 70 | s = "abcd" 71 | p = "abcd" 72 | self.assertTrue(Solution().isMatch(s, p)) 73 | 74 | def test_no_symbol_not_equal_0(self): 75 | s = "abcd" 76 | p = "efgh" 77 | self.assertFalse(Solution().isMatch(s, p)) 78 | 79 | def test_no_symbol_not_equal_1(self): 80 | s = "ab" 81 | p = "abb" 82 | self.assertFalse(Solution().isMatch(s, p)) 83 | 84 | def test_symbol_0(self): 85 | s = "" 86 | p = "a*" 87 | self.assertTrue(Solution().isMatch(s, p)) 88 | 89 | def test_symbol_1(self): 90 | s = "a" 91 | p = "ab*" 92 | self.assertTrue(Solution().isMatch(s, p)) 93 | 94 | def test_symbol_2(self): 95 | # E.g. 96 | # s a b b 97 | # p 1 0 0 0 98 | # a 0 1 0 0 99 | # b 0 0 1 0 100 | # * 0 1 1 1 101 | s = "abb" 102 | p = "ab*" 103 | self.assertTrue(Solution().isMatch(s, p)) 104 | 105 | 106 | if __name__ == "__main__": 107 | unittest.main() 108 | -------------------------------------------------------------------------------- /dp/word_break.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a non-empty string s and a dictionary wordDict 3 | containing a list of non-empty words, 4 | determine if s can be segmented into a space-separated 5 | sequence of one or more dictionary words. 6 | You may assume the dictionary does not contain duplicate words. 7 | 8 | For example, given 9 | s = "leetcode", 10 | dict = ["leet", "code"]. 11 | 12 | Return true because "leetcode" can be segmented as "leet code". 13 | """ 14 | 15 | 16 | """ 17 | s = abc word_dict = ["a","bc"] 18 | True False False False 19 | 20 | """ 21 | 22 | 23 | # TC: O(N^2) SC: O(N) 24 | def word_break(s, word_dict): 25 | """ 26 | :type s: str 27 | :type word_dict: Set[str] 28 | :rtype: bool 29 | """ 30 | dp = [False] * (len(s)+1) 31 | dp[0] = True 32 | for i in range(1, len(s)+1): 33 | for j in range(0, i): 34 | if dp[j] and s[j:i] in word_dict: 35 | dp[i] = True 36 | break 37 | return dp[-1] 38 | 39 | 40 | if __name__ == "__main__": 41 | s = "keonkim" 42 | dic = ["keon", "kim"] 43 | 44 | print(word_break(s, dic)) 45 | -------------------------------------------------------------------------------- /graph/clone_graph.py: -------------------------------------------------------------------------------- 1 | """ 2 | Clone an undirected graph. Each node in the graph contains a label and a list 3 | of its neighbors. 4 | 5 | 6 | OJ's undirected graph serialization: 7 | Nodes are labeled uniquely. 8 | 9 | We use # as a separator for each node, and , as a separator for node label and 10 | each neighbor of the node. 11 | As an example, consider the serialized graph {0,1,2#1,2#2,2}. 12 | 13 | The graph has a total of three nodes, and therefore contains three parts as 14 | separated by #. 15 | 16 | First node is labeled as 0. Connect node 0 to both nodes 1 and 2. 17 | Second node is labeled as 1. Connect node 1 to node 2. 18 | Third node is labeled as 2. Connect node 2 to node 2 (itself), thus forming a 19 | self-cycle. 20 | Visually, the graph looks like the following: 21 | 22 | 1 23 | / \ 24 | / \ 25 | 0 --- 2 26 | / \ 27 | \_/ 28 | """ 29 | 30 | 31 | # Definition for a undirected graph node 32 | # class UndirectedGraphNode: 33 | # def __init__(self, x): 34 | # self.label = x 35 | # self.neighbors = [] 36 | 37 | 38 | # BFS 39 | def cloneGraph1(self, node): 40 | if not node: 41 | return 42 | nodeCopy = UndirectedGraphNode(node.label) 43 | dic = {node: nodeCopy} 44 | queue = collections.deque([node]) 45 | while queue: 46 | node = queue.popleft() 47 | for neighbor in node.neighbors: 48 | if neighbor not in dic: # neighbor is not visited 49 | neighborCopy = UndirectedGraphNode(neighbor.label) 50 | dic[neighbor] = neighborCopy 51 | dic[node].neighbors.append(neighborCopy) 52 | queue.append(neighbor) 53 | else: 54 | dic[node].neighbors.append(dic[neighbor]) 55 | return nodeCopy 56 | 57 | # DFS iteratively 58 | def cloneGraph2(self, node): 59 | if not node: 60 | return 61 | nodeCopy = UndirectedGraphNode(node.label) 62 | dic = {node: nodeCopy} 63 | stack = [node] 64 | while stack: 65 | node = stack.pop() 66 | for neighbor in node.neighbors: 67 | if neighbor not in dic: 68 | neighborCopy = UndirectedGraphNode(neighbor.label) 69 | dic[neighbor] = neighborCopy 70 | dic[node].neighbors.append(neighborCopy) 71 | stack.append(neighbor) 72 | else: 73 | dic[node].neighbors.append(dic[neighbor]) 74 | return nodeCopy 75 | 76 | # DFS recursively 77 | def cloneGraph(self, node): 78 | if not node: 79 | return 80 | nodeCopy = UndirectedGraphNode(node.label) 81 | dic = {node: nodeCopy} 82 | self.dfs(node, dic) 83 | return nodeCopy 84 | 85 | def dfs(self, node, dic): 86 | for neighbor in node.neighbors: 87 | if neighbor not in dic: 88 | neighborCopy = UndirectedGraphNode(neighbor.label) 89 | dic[neighbor] = neighborCopy 90 | dic[node].neighbors.append(neighborCopy) 91 | self.dfs(neighbor, dic) 92 | else: 93 | dic[node].neighbors.append(dic[neighbor]) 94 | -------------------------------------------------------------------------------- /graph/find_path.py: -------------------------------------------------------------------------------- 1 | myGraph = {'A': ['B', 'C'], 2 | 'B': ['C', 'D'], 3 | 'C': ['D', 'F'], 4 | 'D': ['C'], 5 | 'E': ['F'], 6 | 'F': ['C']} 7 | 8 | # find path from start to end using recursion with backtracking 9 | def find_path(graph, start, end, path=[]): 10 | path = path + [start] 11 | if (start == end): 12 | return path 13 | if not start in graph: 14 | return None 15 | for node in graph[start]: 16 | if node not in path: 17 | newpath = find_path(graph, node, end, path) 18 | return newpath 19 | return None 20 | 21 | # find all path 22 | def find_all_path(graph, start, end, path=[]): 23 | path = path + [start] 24 | print(path) 25 | if (start == end): 26 | return [path] 27 | if not start in graph: 28 | return None 29 | paths = [] 30 | for node in graph[start]: 31 | if node not in path: 32 | newpaths = find_all_path(graph, node, end, path) 33 | for newpath in newpaths: 34 | paths.append(newpath) 35 | return paths 36 | 37 | def find_shortest_path(graph, start, end, path=[]): 38 | path = path + [start] 39 | if start == end: 40 | return path 41 | if start not in graph: 42 | return None 43 | shortest = None 44 | for node in graph[start]: 45 | if node not in path: 46 | newpath = find_shortest_path(graph, start, end, path) 47 | if newpath: 48 | if not shortest or len(newpath) < len(shortest): 49 | shortest = newpath 50 | return shortest 51 | 52 | print(find_all_path(myGraph, 'A', 'F')) 53 | # print(find_shortest_path(myGraph, 'A', 'D')) 54 | -------------------------------------------------------------------------------- /graph/graph.py: -------------------------------------------------------------------------------- 1 | class Graph: 2 | def __init__(self, node, edges, source): 3 | pass 4 | -------------------------------------------------------------------------------- /graph/traversal.py: -------------------------------------------------------------------------------- 1 | graph = {'A': set(['B', 'C', 'F']), 2 | 'B': set(['A', 'D', 'E']), 3 | 'C': set(['A', 'F']), 4 | 'D': set(['B']), 5 | 'E': set(['B', 'F']), 6 | 'F': set(['A', 'C', 'E'])} 7 | 8 | # dfs and bfs are the ultimately same except that they are visiting nodes in 9 | # different order. To simulate this ordering we would use stack for dfs and 10 | # queue for bfs. 11 | # 12 | 13 | def dfs_traverse(graph, start): 14 | visited, stack = set(), [start] 15 | while stack: 16 | node = stack.pop() 17 | if node not in visited: 18 | visited.add(node) 19 | for nextNode in graph[node]: 20 | if nextNode not in visited: 21 | stack.append(nextNode) 22 | return visited 23 | 24 | # print(dfs_traverse(graph, 'A')) 25 | 26 | 27 | def bfs_traverse(graph, start): 28 | visited, queue = set(), [start] 29 | while queue: 30 | node = queue.pop(0) 31 | if node not in visited: 32 | visited.add(node) 33 | for nextNode in graph[node]: 34 | if nextNode not in visited: 35 | queue.append(nextNode) 36 | return visited 37 | 38 | # print(bfs_traverse(graph, 'A')) 39 | 40 | def dfs_traverse_recursive(graph, start, visited=None): 41 | if visited is None: 42 | visited = set() 43 | visited.add(start) 44 | for nextNode in graph[start]: 45 | if nextNode not in visited: 46 | dfs_traverse_recursive(graph, nextNode, visited) 47 | return visited 48 | 49 | # print(dfs_traverse_recursive(graph, 'A')) 50 | 51 | # def find_path(graph, start, end, visited=[]): 52 | # # basecase 53 | # visitied = visited + [start] 54 | # if start == end: 55 | # return visited 56 | # if start not in graph: 57 | # return None 58 | # for node in graph[start]: 59 | # if node not in visited: 60 | # new_visited = find_path(graph, node, end, visited) 61 | # return new_visited 62 | # return None 63 | 64 | # print(find_path(graph, 'A', 'F')) 65 | 66 | 67 | -------------------------------------------------------------------------------- /heap/merge_sorted_k_lists.py: -------------------------------------------------------------------------------- 1 | """ 2 | Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 3 | """ 4 | 5 | # Definition for singly-linked list. 6 | # class ListNode(object): 7 | # def __init__(self, x): 8 | # self.val = x 9 | # self.next = None 10 | 11 | from heapq import heappush, heappop, heapreplace, heapify 12 | 13 | def mergeKLists(lists): 14 | dummy = node = ListNode(0) 15 | h = [(n.val, n) for n in lists if n] 16 | heapify(h) 17 | while h: 18 | v, n = h[0] 19 | if n.next is None: 20 | heappop(h) #only change heap size when necessary 21 | else: 22 | heapreplace(h, (n.next.val, n.next)) 23 | node.next = n 24 | node = node.next 25 | 26 | return dummy.next 27 | 28 | from Queue import PriorityQueue 29 | 30 | def merge_k_lists(lists): 31 | dummy = ListNode(None) 32 | curr = dummy 33 | q = PriorityQueue() 34 | for node in lists: 35 | if node: q.put((node.val,node)) 36 | while q.qsize()>0: 37 | curr.next = q.get()[1] 38 | curr=curr.next 39 | if curr.next: q.put((curr.next.val, curr.next)) 40 | return dummy.next 41 | 42 | 43 | """ 44 | I think my code's complexity is also O(nlogk) and not using heap or priority queue, 45 | n means the total elements and k means the size of list. 46 | 47 | The mergeTwoLists functiony in my code comes from the problem Merge Two Sorted Lists 48 | whose complexity obviously is O(n), n is the sum of length of l1 and l2. 49 | 50 | To put it simpler, assume the k is 2^x, So the progress of combination is like a full binary tree, 51 | from bottom to top. So on every level of tree, the combination complexity is n, 52 | beacause every level have all n numbers without repetition. 53 | The level of tree is x, ie logk. So the complexity is O(nlogk). 54 | 55 | for example, 8 ListNode, and the length of every ListNode is x1, x2, 56 | x3, x4, x5, x6, x7, x8, total is n. 57 | 58 | on level 3: x1+x2, x3+x4, x5+x6, x7+x8 sum: n 59 | 60 | on level 2: x1+x2+x3+x4, x5+x6+x7+x8 sum: n 61 | 62 | on level 1: x1+x2+x3+x4+x5+x6+x7+x8 sum: n 63 | """ 64 | -------------------------------------------------------------------------------- /heap/skyline.py: -------------------------------------------------------------------------------- 1 | """ 2 | A city's skyline is the outer contour of the silhouette formed by all the buildings 3 | in that city when viewed from a distance. 4 | Now suppose you are given the locations and height of all the buildings 5 | as shown on a cityscape photo (Figure A), 6 | write a program to output the skyline formed by these buildings collectively (Figure B). 7 | 8 | The geometric information of each building is represented by a triplet of integers [Li, Ri, Hi], 9 | where Li and Ri are the x coordinates of the left and right edge of the ith building, respectively, 10 | and Hi is its height. It is guaranteed that 0 ≤ Li, Ri ≤ INT_MAX, 0 < Hi ≤ INT_MAX, and Ri - Li > 0. 11 | You may assume all buildings are perfect rectangles grounded on an absolutely flat surface at height 0. 12 | 13 | For instance, the dimensions of all buildings in Figure A are recorded as: 14 | [ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ] . 15 | 16 | The output is a list of "key points" (red dots in Figure B) in the format of 17 | [ [x1,y1], [x2, y2], [x3, y3], ... ] 18 | that uniquely defines a skyline. 19 | A key point is the left endpoint of a horizontal line segment. Note that the last key point, 20 | where the rightmost building ends, 21 | is merely used to mark the termination of the skyline, and always has zero height. 22 | Also, the ground in between any two adjacent buildings should be considered part of the skyline contour. 23 | 24 | For instance, the skyline in Figure B should be represented as:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ]. 25 | 26 | Notes: 27 | 28 | The number of buildings in any input list is guaranteed to be in the range [0, 10000]. 29 | The input list is already sorted in ascending order by the left x position Li. 30 | The output list must be sorted by the x position. 31 | There must be no consecutive horizontal lines of equal height in the output skyline. For instance, 32 | [...[2 3], [4 5], [7 5], [11 5], [12 7]...] is not acceptable; the three lines of height 5 should be merged 33 | into one in the final output as such: [...[2 3], [4 5], [12 7], ...] 34 | 35 | """ 36 | 37 | import heapq 38 | 39 | def get_skyline(LRH): 40 | """ 41 | Wortst Time Complexity: O(NlogN) 42 | :type buildings: List[List[int]] 43 | :rtype: List[List[int]] 44 | """ 45 | skyline, live = [], [] 46 | i, n = 0, len(LRH) 47 | while i < n or live: 48 | if not live or i < n and LRH[i][0] <= -live[0][1]: 49 | x = LRH[i][0] 50 | while i < n and LRH[i][0] == x: 51 | heapq.heappush(live, (-LRH[i][2], -LRH[i][1])) 52 | i += 1 53 | else: 54 | x = -live[0][1] 55 | while live and -live[0][1] <= x: 56 | heapq.heappop(live) 57 | height = len(live) and -live[0][0] 58 | if not skyline or height != skyline[-1][1]: 59 | skyline += [x, height], 60 | return skyline 61 | 62 | buildings = [ [2, 9, 10], [3, 7, 15], [5, 12, 12], [15, 20, 10], [19, 24, 8] ] 63 | # [ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ] 64 | print(get_skyline(buildings)) 65 | 66 | 67 | -------------------------------------------------------------------------------- /heap/sliding_window_max.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array nums, there is a sliding window of size k 3 | which is moving from the very left of the array to the very right. 4 | You can only see the k numbers in the window. 5 | Each time the sliding window moves right by one position. 6 | 7 | For example, 8 | Given nums = [1,3,-1,-3,5,3,6,7], and k = 3. 9 | 10 | Window position Max 11 | --------------- ----- 12 | [1 3 -1] -3 5 3 6 7 3 13 | 1 [3 -1 -3] 5 3 6 7 3 14 | 1 3 [-1 -3 5] 3 6 7 5 15 | 1 3 -1 [-3 5 3] 6 7 5 16 | 1 3 -1 -3 [5 3 6] 7 6 17 | 1 3 -1 -3 5 [3 6 7] 7 18 | Therefore, return the max sliding window as [3,3,5,5,6,7]. 19 | """ 20 | import collections 21 | 22 | 23 | def max_sliding_window(nums, k): 24 | """ 25 | :type nums: List[int] 26 | :type k: int 27 | :rtype: List[int] 28 | """ 29 | if not nums: 30 | return nums 31 | queue = collections.deque() 32 | res = [] 33 | for num in nums: 34 | if len(queue) < k: 35 | queue.append(num) 36 | else: 37 | res.append(max(queue)) 38 | queue.popleft() 39 | queue.append(num) 40 | res.append(max(queue)) 41 | return res 42 | -------------------------------------------------------------------------------- /linkedlist/add_two_numbers.py: -------------------------------------------------------------------------------- 1 | """ 2 | You are given two non-empty linked lists representing 3 | two non-negative integers. The digits are stored in reverse order 4 | and each of their nodes contain a single digit. 5 | Add the two numbers and return it as a linked list. 6 | 7 | You may assume the two numbers do not contain any leading zero, 8 | except the number 0 itself. 9 | 10 | Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) 11 | Output: 7 -> 0 -> 8 12 | """ 13 | 14 | 15 | class Node: 16 | def __init__(self, x): 17 | self.val = x 18 | self.next = None 19 | 20 | 21 | def add_two_numbers(left:"Node", right:"Node")->"Node": 22 | head = Node(0) 23 | current = head 24 | sum = 0 25 | while left or right: 26 | print("adding: ", left.val, right.val) 27 | sum //= 10 28 | if left: 29 | sum += left.val 30 | left = left.next 31 | if right: 32 | sum += right.val 33 | right = right.next 34 | current.next = Node(sum % 10) 35 | current = current.next 36 | if sum // 10 == 1: 37 | current.next = Node(1) 38 | return head.next 39 | 40 | 41 | if __name__ == "__main__": 42 | left = Node(2) 43 | left.next = Node(4) 44 | left.next.next = Node(3) 45 | 46 | right = Node(5) 47 | right.next = Node(6) 48 | right.next.next = Node(4) 49 | 50 | res = add_two_numbers(left, right) 51 | while res: 52 | print(res.val) 53 | res = res.next 54 | -------------------------------------------------------------------------------- /linkedlist/copy_random_pointer.py: -------------------------------------------------------------------------------- 1 | """ 2 | A linked list is given such that each node contains an additional random 3 | pointer which could point to any node in the list or null. 4 | 5 | Return a deep copy of the list. 6 | """ 7 | 8 | class Solution: 9 | # @param head, a RandomListNode 10 | # @return a RandomListNode 11 | def copyRandomList(self, head): 12 | dic = dict() 13 | m = n = head 14 | while m: 15 | dic[m] = RandomListNode(m.label) 16 | m = m.next 17 | while n: 18 | dic[n].next = dic.get(n.next) 19 | dic[n].random = dic.get(n.random) 20 | n = n.next 21 | return dic.get(head) 22 | 23 | #O(n) 24 | class Solution: 25 | # @param head, a RandomListNode 26 | # @return a RandomListNode 27 | def copyRandomList(self, head): 28 | copy = collections.defaultdict(lambda: RandomListNode(0)) 29 | copy[None] = None 30 | node = head 31 | while node: 32 | copy[node].label = node.label 33 | copy[node].next = copy[node.next] 34 | copy[node].random = copy[node.random] 35 | node = node.next 36 | return copy[head] 37 | -------------------------------------------------------------------------------- /linkedlist/delete_node.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write a function to delete a node (except the tail) 3 | in a singly linked list, given only access to that node. 4 | 5 | Supposed the linked list is 1 -> 2 -> 3 -> 4 and 6 | you are given the third node with value 3, 7 | the linked list should become 1 -> 2 -> 4 after calling your function. 8 | """ 9 | 10 | 11 | def delete_node(node): 12 | node.val = node.next.val 13 | node.next = node.next.next 14 | -------------------------------------------------------------------------------- /linkedlist/first_cyclic_node.py: -------------------------------------------------------------------------------- 1 | # find the first node of a cycle in the linked list. 2 | 3 | # 1 -> 2 -> 3 -> 4 -> 5 -> 1 => 1 4 | # A -> B -> C -> D -> E -> C => C 5 | 6 | def firstCyclicNode(): 7 | pass 8 | 9 | -------------------------------------------------------------------------------- /linkedlist/is_cyclic.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a linked list, determine if it has a cycle in it. 3 | 4 | Follow up: 5 | Can you solve it without using extra space? 6 | """ 7 | 8 | 9 | def is_cyclic(head): 10 | """ 11 | :type head: Node 12 | :rtype: bool 13 | """ 14 | if not head: 15 | return False 16 | runner = head 17 | walker = head 18 | while runner.next and runner.next.next: 19 | runner = runner.next.next 20 | walker = walker.next 21 | if runner == walker: 22 | return True 23 | return False 24 | -------------------------------------------------------------------------------- /linkedlist/is_palindrome.py: -------------------------------------------------------------------------------- 1 | def is_palindrome(head): 2 | if not head: 3 | return True 4 | # split the list to two parts 5 | fast, slow = head.next, head 6 | while fast and fast.next: 7 | fast = fast.next.next 8 | slow = slow.next 9 | second = slow.next 10 | slow.next = None # Don't forget here! But forget still works! 11 | # reverse the second part 12 | node = None 13 | while second: 14 | nxt = second.next 15 | second.next = node 16 | node = second 17 | second = nxt 18 | # compare two parts 19 | # second part has the same or one less node 20 | while node: 21 | if node.val != head.val: 22 | return False 23 | node = node.next 24 | head = head.next 25 | return True 26 | 27 | def is_palindrome_stack(head): 28 | if not head or not head.next: 29 | return True 30 | 31 | # 1. Get the midpoint (slow) 32 | slow = fast = cur = head 33 | while fast and fast.next: 34 | fast, slow = fast.next.next, slow.next 35 | 36 | # 2. Push the second half into the stack 37 | stack = [slow.val] 38 | while slow.next: 39 | slow = slow.next 40 | stack.append(slow.val) 41 | 42 | # 3. Comparison 43 | while stack: 44 | if stack.pop() != cur.val: 45 | return False 46 | cur = cur.next 47 | 48 | return True 49 | -------------------------------------------------------------------------------- /linkedlist/kth_to_last.py: -------------------------------------------------------------------------------- 1 | class Node(): 2 | def __init__(self, val = None): 3 | self.val = val 4 | self.next = None 5 | 6 | def printKthToLast(head): 7 | """ 8 | Time Complexity: O() 9 | Space Complexity: O() 10 | """ 11 | pass 12 | 13 | def printLinkedList(head): 14 | string = "" 15 | while head.next: 16 | string += head.val + " -> " 17 | head = head.next 18 | string += head.val 19 | print(string) 20 | 21 | # A A B C D C F G 22 | 23 | a1 = Node("A") 24 | a2 = Node("A") 25 | b = Node("B") 26 | c1 = Node("C") 27 | d = Node("D") 28 | c2 = Node("C") 29 | f = Node("F") 30 | g = Node("G") 31 | 32 | a1.next = a2 33 | a2.next = b 34 | b.next = c1 35 | c1.next = d 36 | d.next = c2 37 | c2.next = f 38 | f.next = g 39 | 40 | # removeDups(a1) 41 | # printLinkedList(a1) 42 | # removeDupsWithoutSet(a1) 43 | # printLinkedList(a1) 44 | 45 | -------------------------------------------------------------------------------- /linkedlist/linkedlist.py: -------------------------------------------------------------------------------- 1 | # Pros 2 | # Linked Lists have constant-time insertions and deletions in any position, 3 | # in comparison, arrays require O(n) time to do the same thing. 4 | # Linked lists can continue to expand without having to specify 5 | # their size ahead of time (remember our lectures on Array sizing 6 | # form the Array Sequence section of the course!) 7 | 8 | # Cons 9 | # To access an element in a linked list, you need to take O(k) time 10 | # to go from the head of the list to the kth element. 11 | # In contrast, arrays have constant time operations to access 12 | # elements in an array. 13 | 14 | class DoublyLinkedListNode(object): 15 | def __init__(self, value): 16 | self.value = value 17 | self.next = None 18 | self.prev = None 19 | 20 | 21 | class SinglyLinkedListNode(object): 22 | def __init__(self, value): 23 | self.value = value 24 | self.next = None 25 | -------------------------------------------------------------------------------- /linkedlist/remove_duplicates.py: -------------------------------------------------------------------------------- 1 | class Node(): 2 | def __init__(self, val = None): 3 | self.val = val 4 | self.next = None 5 | 6 | def removeDups(head): 7 | """ 8 | Time Complexity: O(N) 9 | Space Complexity: O(N) 10 | """ 11 | hashset = set() 12 | prev = Node() 13 | while head: 14 | if head.val in hashset: 15 | prev.next = head.next 16 | else: 17 | hashset.add(head.val) 18 | prev = head 19 | head = head.next 20 | 21 | def removeDupsWithoutSet(head): 22 | """ 23 | Time Complexity: O(N^2) 24 | Space Complexity: O(1) 25 | """ 26 | current = head 27 | while current: 28 | runner = current 29 | while runner.next: 30 | if runner.next.val == current.val: 31 | runner.next = runner.next.next 32 | else: 33 | runner = runner.next 34 | current = current.next 35 | 36 | def printLinkedList(head): 37 | string = "" 38 | while head.next: 39 | string += head.val + " -> " 40 | head = head.next 41 | string += head.val 42 | print(string) 43 | 44 | # A A B C D C F G 45 | 46 | a1 = Node("A") 47 | a2 = Node("A") 48 | b = Node("B") 49 | c1 = Node("C") 50 | d = Node("D") 51 | c2 = Node("C") 52 | f = Node("F") 53 | g = Node("G") 54 | 55 | a1.next = a2 56 | a2.next = b 57 | b.next = c1 58 | c1.next = d 59 | d.next = c2 60 | c2.next = f 61 | f.next = g 62 | 63 | removeDups(a1) 64 | printLinkedList(a1) 65 | removeDupsWithoutSet(a1) 66 | printLinkedList(a1) 67 | 68 | -------------------------------------------------------------------------------- /linkedlist/reverse.py: -------------------------------------------------------------------------------- 1 | """ 2 | Reverse a singly linked list. 3 | """ 4 | 5 | 6 | def reverse_list(head): 7 | """ 8 | :type head: ListNode 9 | :rtype: ListNode 10 | """ 11 | if not head or not head.next: 12 | return head 13 | prev = None 14 | while head: 15 | current = head 16 | head = head.next 17 | current.next = prev 18 | prev = current 19 | return prev 20 | -------------------------------------------------------------------------------- /linkedlist/rotate_list.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a list, rotate the list to the right by k places, 3 | where k is non-negative. 4 | 5 | For example: 6 | Given 1->2->3->4->5->NULL and k = 2, 7 | return 4->5->1->2->3->NULL. 8 | """ 9 | 10 | # Definition for singly-linked list. 11 | # class ListNode(object): 12 | # def __init__(self, x): 13 | # self.val = x 14 | # self.next = None 15 | 16 | 17 | def rotate_right(head, k): 18 | """ 19 | :type head: ListNode 20 | :type k: int 21 | :rtype: ListNode 22 | """ 23 | if not head or not head.next: 24 | return head 25 | current = head 26 | length = 1 27 | # count length of the list 28 | while current.next: 29 | current = current.next 30 | length += 1 31 | # make it circular 32 | current.next = head 33 | k = k % length 34 | # rotate until length-k 35 | for i in range(length-k): 36 | current = current.next 37 | head = current.next 38 | current.next = None 39 | return head 40 | -------------------------------------------------------------------------------- /linkedlist/swap_in_pairs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a linked list, swap every two adjacent nodes 3 | and return its head. 4 | 5 | For example, 6 | Given 1->2->3->4, you should return the list as 2->1->4->3. 7 | 8 | Your algorithm should use only constant space. 9 | You may not modify the values in the list, 10 | only nodes itself can be changed. 11 | """ 12 | 13 | 14 | class Node: 15 | def __init__(self, x=0): 16 | self.val = x 17 | self.next = None 18 | 19 | 20 | def swap_pairs(head:"Node")->"Node": 21 | if not head: 22 | return head 23 | start = Node() 24 | pre = start 25 | pre.next = head 26 | while pre.next and pre.next.next: 27 | a = pre.next 28 | b = pre.next.next 29 | pre.next, a.next, b.next = b, b.next, a 30 | pre = a 31 | return start.next 32 | 33 | 34 | if __name__ == "__main__": 35 | n = Node(1) 36 | n.next = Node(2) 37 | n.next.next = Node(3) 38 | n.next.next.next = Node(4) 39 | res = swap_pairs(n) 40 | 41 | while res: 42 | print(res.val, end=" ") 43 | res = res.next 44 | print("should be 2 1 4 3 ") 45 | 46 | -------------------------------------------------------------------------------- /map/hashtable.py: -------------------------------------------------------------------------------- 1 | """ 2 | MAP Abstract Data Type 3 | Map() Create a new, empty map. It returns an empty map collection. 4 | put(key,val) Add a new key-value pair to the map. If the key is already in the map then replace the old value with the new value. 5 | get(key) Given a key, return the value stored in the map or None otherwise. 6 | del Delete the key-value pair from the map using a statement of the form del map[key]. 7 | len() Return the number of key-value pairs stored in the map. 8 | in Return True for a statement of the form key in map, if the given key is in the map, False otherwise. 9 | """ 10 | class HashTable(object): 11 | def __init__(self, size = 11): 12 | self.size = size 13 | self.keys = [None] * size # keys 14 | self.values = [None] * size # values 15 | 16 | def put(self, key, value): 17 | hashval = self.hash(key) 18 | 19 | if hashval not in keys: 20 | self.keys[hashval] = key 21 | self.values[hashval] = value 22 | else: 23 | if self.keys[hashval] == key: # replace 24 | self.values[hashval] = value 25 | else: # probing 26 | rehashval = self.rehash(key) 27 | while self.keys[rehashval] is not None and \ 28 | self.keys[rehashval] != key: 29 | rehashval = self.rehash(rehashval) 30 | if keys[rehashval] is None: 31 | self.keys[rehashval] = key 32 | self.values[rehashval] = value 33 | else: 34 | self.values[rehashval] = value # replacee 35 | 36 | def get(self, key): 37 | pass 38 | 39 | def hash(self, key): 40 | return key % self.size 41 | 42 | def rehash(self, oldhash): 43 | """ 44 | linear probing 45 | """ 46 | return (oldhash + 1) % self.size 47 | 48 | def __getitem__(self,key): 49 | return self.get(key) 50 | 51 | def __setitem__(self, key, value): 52 | self.put(key, value) 53 | 54 | 55 | -------------------------------------------------------------------------------- /map/longest_common_subsequence.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given string a and b, with b containing all distinct characters, 3 | find the longest common subsequence's 4 | 5 | length. Expected complexity O(nlogn). 6 | """ 7 | 8 | 9 | def max_common_sub_string(s1, s2): 10 | # Assuming s2 has all unique chars 11 | s2dic = {s2[i]: i for i in xrange(len(s2))} 12 | maxr = 0 13 | subs = '' 14 | i = 0 15 | while i < len(s1): 16 | if s1[i] in s2dic: 17 | j = s2dic[s1[i]] 18 | k = i 19 | while j < len(s2) and k < len(s1) and s1[k] == s2[j]: 20 | k += 1 21 | j += 1 22 | if k - i > maxr: 23 | maxr = k-i 24 | subs = s1[i:k] 25 | i = k 26 | else: 27 | i += 1 28 | return subs 29 | -------------------------------------------------------------------------------- /map/randomized_set.py: -------------------------------------------------------------------------------- 1 | """ 2 | Design a data structure that supports all following operations 3 | in average O(1) time. 4 | 5 | insert(val): Inserts an item val to the set if not already present. 6 | remove(val): Removes an item val from the set if present. 7 | getRandom: Returns a random element from current set of elements. 8 | Each element must have the same probability of being returned. 9 | """ 10 | 11 | 12 | import random 13 | 14 | 15 | class RandomizedSet: 16 | def __init__(self): 17 | self.nums = [] 18 | self.idxs = {} 19 | 20 | def insert(self, val): 21 | if val not in self.idxs: 22 | self.nums.append(val) 23 | self.idxs[val] = len(self.nums)-1 24 | return True 25 | return False 26 | 27 | def remove(self, val): 28 | if val in self.idxs: 29 | idx, last = self.idxs[val], self.nums[-1] 30 | self.nums[idx], self.idxs[last] = last, idx 31 | self.nums.pop() 32 | self.idxs.pop(val, 0) 33 | return True 34 | return False 35 | 36 | def get_random(self): 37 | idx = random.randint(0, len(self.nums)-1) 38 | return self.nums[idx] 39 | 40 | 41 | if __name__ == "__main__": 42 | rs = RandomizedSet() 43 | print("insert 1: ", rs.insert(1)) 44 | print("insert 2: ", rs.insert(2)) 45 | print("insert 3: ", rs.insert(3)) 46 | print("insert 4: ", rs.insert(4)) 47 | print("remove 3: ", rs.remove(3)) 48 | print("remove 3: ", rs.remove(3)) 49 | print("remove 1: ", rs.remove(1)) 50 | print("random: ", rs.get_random()) 51 | print("random: ", rs.get_random()) 52 | print("random: ", rs.get_random()) 53 | print("random: ", rs.get_random()) 54 | -------------------------------------------------------------------------------- /map/valid_sudoku.py: -------------------------------------------------------------------------------- 1 | """ 2 | Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. 3 | 4 | The Sudoku board could be partially filled, where empty cells are filled with 5 | the character '.'. 6 | """ 7 | 8 | def is_valid_sudoku(self, board): 9 | seen = [] 10 | for i, row in enumerate(board): 11 | for j, c in enumerate(row): 12 | if c != '.': 13 | seen += [(c,j),(i,c),(i/3,j/3,c)] 14 | return len(seen) == len(set(seen)) 15 | -------------------------------------------------------------------------------- /math/extended_gcd.py: -------------------------------------------------------------------------------- 1 | """ 2 | extended GCD algorithm 3 | return s,t,g 4 | such that a s + b t = GCD(a, b) 5 | and s and t are coprime 6 | """ 7 | 8 | def extended_gcd(a,b): 9 | old_s, s = 1, 0 10 | old_t, t = 0, 1 11 | old_r, r = a, b 12 | 13 | while r != 0: 14 | quotient = old_r / r 15 | 16 | old_r, r = r, old_r - quotient * r 17 | old_s, s = s, old_s - quotient * s 18 | old_t, t = t, old_t - quotient * t 19 | 20 | return old_s, old_t, old_r -------------------------------------------------------------------------------- /math/gcd.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Computes gcd of integers x,y using Euclid's Algorithm 3 | ''' 4 | 5 | 6 | def gcd(x,y): 7 | x = abs(x) #gcd(a,b) = gcd(|a|,b) = gcd(a,|b|) = gcd(|a|,|b|) 8 | y = abs(y) 9 | if x>y: # To ensure x<=y 10 | x,y = y,x 11 | if x==0: 12 | return y 13 | return gcd(y % x, x) # Euclid's algorithm 14 | -------------------------------------------------------------------------------- /math/generate_strobogrammtic.py: -------------------------------------------------------------------------------- 1 | """ 2 | A strobogrammatic number is a number that looks 3 | the same when rotated 180 degrees (looked at upside down). 4 | 5 | Find all strobogrammatic numbers that are of length = n. 6 | 7 | For example, 8 | Given n = 2, return ["11","69","88","96"]. 9 | """ 10 | 11 | 12 | def gen_strobogrammatic(n): 13 | """ 14 | :type n: int 15 | :rtype: List[str] 16 | """ 17 | result = helper(n, n) 18 | return result 19 | 20 | 21 | def helper(n, length): 22 | if n == 0: 23 | return [""] 24 | if n == 1: 25 | return ["1", "0", "8"] 26 | middles = helper(n-2, length) 27 | result = [] 28 | for middle in middles: 29 | if n != length: 30 | result.append("0" + middle + "0") 31 | result.append("8" + middle + "8") 32 | result.append("1" + middle + "1") 33 | result.append("9" + middle + "6") 34 | result.append("6" + middle + "9") 35 | return result 36 | 37 | 38 | def strobogrammaticInRange(low, high): 39 | """ 40 | :type low: str 41 | :type high: str 42 | :rtype: int 43 | """ 44 | res = [] 45 | count = 0 46 | for i in range(len(low), len(high)+1): 47 | res.extend(helper2(i, i)) 48 | for perm in res: 49 | if len(perm) == len(low) and int(perm) < int(low): 50 | continue 51 | elif len(perm) == len(high) and int(perm) > int(high): 52 | continue 53 | else: 54 | count += 1 55 | return count 56 | 57 | 58 | def helper2(self, n, length): 59 | if n == 0: 60 | return [""] 61 | if n == 1: 62 | return ["0", "8", "1"] 63 | mids = helper(n-2, length) 64 | res = [] 65 | for mid in mids: 66 | if n != length: 67 | res.append("0"+mid+"0") 68 | res.append("1"+mid+"1") 69 | res.append("6"+mid+"9") 70 | res.append("9"+mid+"6") 71 | res.append("8"+mid+"8") 72 | return res 73 | -------------------------------------------------------------------------------- /math/is_strobogrammatic.py: -------------------------------------------------------------------------------- 1 | """ 2 | A strobogrammatic number is a number that looks 3 | the same when rotated 180 degrees (looked at upside down). 4 | 5 | Write a function to determine if a number is strobogrammatic. 6 | The number is represented as a string. 7 | 8 | For example, the numbers "69", "88", and "818" are all strobogrammatic. 9 | """ 10 | 11 | 12 | def is_strobogrammatic(num): 13 | """ 14 | :type num: str 15 | :rtype: bool 16 | """ 17 | comb = "00 11 88 69 96" 18 | i = 0 19 | j = len(num) - 1 20 | while i <= j: 21 | x = comb.find(num[i]+num[j]) 22 | if x == -1: 23 | return False 24 | i += 1 25 | j -= 1 26 | return True 27 | -------------------------------------------------------------------------------- /math/nth_digit.py: -------------------------------------------------------------------------------- 1 | """ 2 | find nth digit 3 | 1. find the length of the number where the nth digit is from. 4 | 2. find the actual number where the nth digit is from 5 | 3. find the nth digit and return 6 | """ 7 | 8 | 9 | def find_nth_digit(n): 10 | len = 1 11 | count = 9 12 | start = 1 13 | while n > len * count: 14 | n -= len * count 15 | len += 1 16 | count *= 10 17 | start *= 10 18 | start += (n-1) / len 19 | s = str(start) 20 | return int(s[(n-1) % len]) 21 | -------------------------------------------------------------------------------- /math/prime_test.py: -------------------------------------------------------------------------------- 1 | ''' 2 | prime_test(n) returns a True if n is a prime number else it returns False 3 | ''' 4 | 5 | 6 | def prime_test(n): 7 | if n <= 1: 8 | return False 9 | if n==2 or n==3: 10 | return True 11 | if n%2==0 or n%3==0: 12 | return False 13 | j = 6 14 | while(j*j < n): 15 | if n%(j-1)==0 or n%(j+1)==0: 16 | return False 17 | j += 6 18 | return True 19 | -------------------------------------------------------------------------------- /math/primes_sieve_of_eratosthenes.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Using sieve of Eratosthenes, primes(x) returns list of all primes less than x 3 | ''' 4 | 5 | def primes(x): 6 | assert(x>=0) 7 | sieve = [1 for v in range(x+1)] # Sieve 8 | primes = [] # List of Primes 9 | for i in range(2,x+1): 10 | if sieve[i]==1: 11 | primes.append(i) 12 | for j in range(i,x+1,i): 13 | sieve[j]=0 14 | return primes 15 | -------------------------------------------------------------------------------- /math/pythagoras.py: -------------------------------------------------------------------------------- 1 | """ 2 | input two of the three side in right angled triangle and return the third. use "?" to indicate the unknown side. 3 | """ 4 | 5 | def pythagoras(opposite,adjacent,hypotenuse): 6 | try: 7 | if opposite == str("?"): 8 | return ("Opposite = " + str(((hypotenuse**2) - (adjacent**2))**0.5)) 9 | elif adjacent == str("?"): 10 | return ("Adjacent = " + str(((hypotenuse**2) - (opposite**2))**0.5)) 11 | elif hypotenuse == str("?"): 12 | return ("Hypotenuse = " + str(((opposite**2) + (adjacent**2))**0.5)) 13 | else: 14 | return "You already know the answer!" 15 | except: 16 | print ("Error, check your input. You must know 2 of the 3 variables.") 17 | -------------------------------------------------------------------------------- /math/rabin_miller.py: -------------------------------------------------------------------------------- 1 | import random,sys 2 | 3 | # factor n into a power of 2 times an odd number 4 | def pow2_factor(n): 5 | power = 0 6 | while n % 2 == 0: 7 | n /= 2 8 | power += 1 9 | return power, n 10 | 11 | """ 12 | Rabin-Miller primality test 13 | returning False implies that n is guarenteed composite 14 | returning True means that n is probably prime 15 | with a 4 ** -k chance of being wrong 16 | """ 17 | def is_prime(n, k): 18 | r, d = pow2_factor(n - 1) 19 | 20 | """ 21 | returns true if a is a valid 'witness' for n 22 | a valid witness increases chances of n being prime 23 | an invalid witness guarentees n is composite 24 | """ 25 | def valid_witness(a): 26 | x = pow(a, d, n) 27 | 28 | if x == 1 or x == n - 1: 29 | return False 30 | 31 | for _ in range(r - 1): 32 | x = pow(x, 2, n) 33 | 34 | if x == 1: 35 | return True 36 | if x == n - 1: 37 | return False 38 | 39 | return True 40 | 41 | for _ in range(k): 42 | if valid_witness(random.randrange(2, n - 2)): 43 | return False 44 | 45 | return True -------------------------------------------------------------------------------- /math/rsa.py: -------------------------------------------------------------------------------- 1 | """ 2 | RSA encryption algorithm 3 | a method for encrypting a number that uses seperate encryption and decryption keys 4 | this file only implements the key generation algorithm 5 | 6 | there are three important numbers in RSA called n, e, and d 7 | e is called the encryption exponent 8 | d is called the decryption exponent 9 | n is called the modulus 10 | 11 | these three numbers satisfy 12 | ((x ** e) ** d) % n == x % n 13 | 14 | to use this system for encryption, n and e are made publicly available, and d is kept secret 15 | a number x can be encrypted by computing (x ** e) % d 16 | the original number can then be recovered by computing (E ** d) % n, where E is 17 | the encrypted number 18 | 19 | fortunately, python provides a three argument version of pow() that can compute powers modulo 20 | a number very quickly: 21 | (a ** b) % c == pow(a,b,c) 22 | """ 23 | 24 | import random 25 | 26 | from rabin_miller import * # is_prime 27 | from extended_gcd import * # extended_gcd 28 | 29 | """ 30 | generate a prime with k bits 31 | """ 32 | def genprime(k): 33 | while True: 34 | n = random.randrange(2 ** (k - 1),2 ** k) 35 | if is_prime(n,128): 36 | return n 37 | 38 | """ 39 | calculate the inverse of a mod m 40 | that is, find b such that (a * b) % m == 1 41 | """ 42 | def modinv(a, m): 43 | x, y, g = extended_gcd(a,m) 44 | return x % m 45 | 46 | """ 47 | the RSA key generating algorithm 48 | k is the number of bits in n 49 | """ 50 | def generate_key(k): 51 | # size in bits of p and q need to add up to the size of n 52 | p_size = k / 2 53 | q_size = k - p_size 54 | 55 | e = genprime(k) # in many cases, e is also chosen to be a small constant 56 | 57 | while True: 58 | p = genprime(k / 2) 59 | if p % e != 1: 60 | break 61 | 62 | while True: 63 | q = genprime(k - k / 2) 64 | if q % e != 1: 65 | break 66 | 67 | n = p * q 68 | l = (p - 1) * (q - 1) # calculate totient function 69 | d = modinv(e,l) 70 | 71 | return n, e, d 72 | 73 | """ 74 | sample usage: 75 | n,e,d = generate_key(1024) 76 | data = 1337 77 | encrypted = pow(data,e,n) 78 | decrypted = pow(encrypted,d,n) 79 | assert decrypted == data 80 | """ -------------------------------------------------------------------------------- /math/sqrt_precision_factor.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a positive integer N and a precision factor P, 3 | write a square root function that produce an output 4 | with a maximum error P from the actual square root of N. 5 | 6 | Example: 7 | Given N = 5 and P = 0.001, can produce output O such that 8 | 2.235 < O > 2.237. Actual square root of 5 being 2.236. 9 | """ 10 | 11 | def square_root(n,p): 12 | guess = float(n) / 2 13 | 14 | while abs(guess * guess - n) > p: 15 | guess = (guess + (n / guess)) / 2 16 | 17 | return guess 18 | -------------------------------------------------------------------------------- /matrix/bomb_enemy.py: -------------------------------------------------------------------------------- 1 | # Given a 2D grid, each cell is either a wall 'W', 2 | # an enemy 'E' or empty '0' (the number zero), 3 | # return the maximum enemies you can kill using one bomb. 4 | # The bomb kills all the enemies in the same row and column from 5 | # the planted point until it hits the wall since the wall is too strong 6 | # to be destroyed. 7 | # Note that you can only put the bomb at an empty cell. 8 | 9 | # Example: 10 | # For the given grid 11 | 12 | # 0 E 0 0 13 | # E 0 W E 14 | # 0 E 0 0 15 | 16 | # return 3. (Placing a bomb at (1,1) kills 3 enemies) 17 | 18 | def max_killed_enemies(grid): 19 | if not grid: return 0 20 | m, n = len(grid), len(grid[0]) 21 | max_killed = 0 22 | row_e, col_e = 0, [0] * n 23 | for i in range(m): 24 | for j in range(n): 25 | if j == 0 or grid[i][j-1] == 'W': 26 | row_e = row_kills(grid, i, j) 27 | 28 | if i == 0 or grid[i-1][j] == 'W': 29 | col_e[j] = col_kills(grid, i, j) 30 | 31 | if grid[i][j] == '0': 32 | max_killed = max(max_killed, row_e + col_e[j]) 33 | 34 | return max_killed 35 | 36 | # calculate killed enemies for row i from column j 37 | def row_kills(grid, i, j): 38 | num = 0 39 | while j < len(grid[0]) and grid[i][j] != 'W': 40 | if grid[i][j] == 'E': 41 | num += 1 42 | j += 1 43 | return num 44 | 45 | # calculate killed enemies for column j from row i 46 | def col_kills(grid, i, j): 47 | num = 0 48 | while i < len(grid) and grid[i][j] != 'W': 49 | if grid[i][j] == 'E': 50 | num += 1 51 | i += 1 52 | return num 53 | 54 | grid = [ 55 | ["0", "E", "0", "E"], 56 | ["E", "E", "E", "0"], 57 | ["E", "0", "W", "E"], 58 | ["0", "E", "0", "0"]] 59 | print(grid) 60 | 61 | print(max_killed_enemies(grid)) 62 | 63 | -------------------------------------------------------------------------------- /matrix/rotate_image.py: -------------------------------------------------------------------------------- 1 | """ 2 | You are given an n x n 2D mat representing an image. 3 | 4 | Rotate the image by 90 degrees (clockwise). 5 | 6 | Follow up: 7 | Could you do this in-place? 8 | """ 9 | 10 | 11 | # clockwise rotate 12 | # first reverse up to down, then swap the symmetry 13 | # 1 2 3 7 8 9 7 4 1 14 | # 4 5 6 => 4 5 6 => 8 5 2 15 | # 7 8 9 1 2 3 9 6 3 16 | 17 | def rotate(mat:"List[List[int]]"): 18 | if not mat: 19 | return mat 20 | mat.reverse() 21 | for i in range(len(mat)): 22 | for j in range(i): 23 | mat[i][j], mat[j][i] = mat[j][i], mat[i][j] 24 | 25 | 26 | if __name__ == "__main__": 27 | mat = [[1,2,3], 28 | [4,5,6], 29 | [7,8,9]] 30 | print(mat) 31 | rotate(mat) 32 | print(mat) 33 | -------------------------------------------------------------------------------- /matrix/sparse_dot_vector.py: -------------------------------------------------------------------------------- 1 | """ 2 | Suppose we have very large sparse vectors, which contains a lot of zeros and double . 3 | 4 | find a data structure to store them 5 | get the dot product of them 6 | 7 | 8 | In this case, we first have to store the sparse vector using hash map. 9 | for example [3,0,0,5,6] -> (0,3) (3,5) (4,6) The key is each element's position and the value is the number. 10 | 11 | Then we have two hash tables, and we have to iterate through them to calculate the dot product 12 | """ 13 | -------------------------------------------------------------------------------- /matrix/sparse_mul.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two sparse matrices A and B, return the result of AB. 3 | 4 | You may assume that A's column number is equal to B's row number. 5 | 6 | Example: 7 | 8 | A = [ 9 | [ 1, 0, 0], 10 | [-1, 0, 3] 11 | ] 12 | 13 | B = [ 14 | [ 7, 0, 0 ], 15 | [ 0, 0, 0 ], 16 | [ 0, 0, 1 ] 17 | ] 18 | 19 | 20 | | 1 0 0 | | 7 0 0 | | 7 0 0 | 21 | AB = | -1 0 3 | x | 0 0 0 | = | -7 0 3 | 22 | | 0 0 1 | 23 | """ 24 | 25 | 26 | # Python solution without table (~156ms): 27 | def multiply(self, A, B): 28 | """ 29 | :type A: List[List[int]] 30 | :type B: List[List[int]] 31 | :rtype: List[List[int]] 32 | """ 33 | if A is None or B is None: return None 34 | m, n, l = len(A), len(A[0]), len(B[0]) 35 | if len(B) != n: 36 | raise Exception("A's column number must be equal to B's row number.") 37 | C = [[0 for _ in range(l)] for _ in range(m)] 38 | for i, row in enumerate(A): 39 | for k, eleA in enumerate(row): 40 | if eleA: 41 | for j, eleB in enumerate(B[k]): 42 | if eleB: C[i][j] += eleA * eleB 43 | return C 44 | 45 | 46 | # Python solution with only one table for B (~196ms): 47 | def multiply(self, A, B): 48 | """ 49 | :type A: List[List[int]] 50 | :type B: List[List[int]] 51 | :rtype: List[List[int]] 52 | """ 53 | if A is None or B is None: return None 54 | m, n, l = len(A), len(A[0]), len(B[0]) 55 | if len(B) != n: 56 | raise Exception("A's column number must be equal to B's row number.") 57 | C = [[0 for _ in range(l)] for _ in range(m)] 58 | tableB = {} 59 | for k, row in enumerate(B): 60 | tableB[k] = {} 61 | for j, eleB in enumerate(row): 62 | if eleB: tableB[k][j] = eleB 63 | for i, row in enumerate(A): 64 | for k, eleA in enumerate(row): 65 | if eleA: 66 | for j, eleB in tableB[k].iteritems(): 67 | C[i][j] += eleA * eleB 68 | return C 69 | 70 | # Python solution with two tables (~196ms): 71 | def multiply(self, A, B): 72 | """ 73 | :type A: List[List[int]] 74 | :type B: List[List[int]] 75 | :rtype: List[List[int]] 76 | """ 77 | if A is None or B is None: return None 78 | m, n = len(A), len(A[0]) 79 | if len(B) != n: 80 | raise Exception("A's column number must be equal to B's row number.") 81 | l = len(B[0]) 82 | table_A, table_B = {}, {} 83 | for i, row in enumerate(A): 84 | for j, ele in enumerate(row): 85 | if ele: 86 | if i not in table_A: table_A[i] = {} 87 | table_A[i][j] = ele 88 | for i, row in enumerate(B): 89 | for j, ele in enumerate(row): 90 | if ele: 91 | if i not in table_B: table_B[i] = {} 92 | table_B[i][j] = ele 93 | C = [[0 for j in range(l)] for i in range(m)] 94 | for i in table_A: 95 | for k in table_A[i]: 96 | if k not in table_B: continue 97 | for j in table_B[k]: 98 | C[i][j] += table_A[i][k] * table_B[k][j] 99 | return C 100 | -------------------------------------------------------------------------------- /matrix/spiral_traversal.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a matrix of m x n elements (m rows, n columns), 3 | return all elements of the matrix in spiral order. 4 | For example, 5 | Given the following matrix: 6 | [ 7 | [ 1, 2, 3 ], 8 | [ 4, 5, 6 ], 9 | [ 7, 8, 9 ] 10 | ] 11 | 12 | 13 | You should return [1,2,3,6,9,8,7,4,5]. 14 | """ 15 | 16 | 17 | def spiral_traversal(matrix): 18 | res = [] 19 | if len(matrix) == 0: 20 | return res 21 | row_begin = 0 22 | row_end = len(matrix) - 1 23 | col_begin = 0 24 | col_end = len(matrix[0]) - 1 25 | 26 | while row_begin <= row_end and col_begin <= col_end: 27 | for i in range(col_begin, col_end+1): 28 | res.append(matrix[row_begin][i]) 29 | row_begin += 1 30 | 31 | for i in range(row_begin, row_end+1): 32 | res.append(matrix[i][col_end]) 33 | col_end -= 1 34 | 35 | if row_begin <= row_end: 36 | for i in range(col_end, col_begin-1, -1): 37 | res.append(matrix[row_end][i]) 38 | row_end -= 1 39 | 40 | if col_begin <= col_end: 41 | for i in range(row_end, row_begin-1, -1): 42 | res.append(matrix[i][col_begin]) 43 | col_begin += 1 44 | 45 | return res 46 | 47 | 48 | if __name__ == "__main__": 49 | mat = [[1, 2, 3], 50 | [4, 5, 6], 51 | [7, 8, 9]] 52 | print(spiral_traversal(mat)) 53 | -------------------------------------------------------------------------------- /queue/__init__.py: -------------------------------------------------------------------------------- 1 | from .queue import * 2 | -------------------------------------------------------------------------------- /queue/max_sliding_window.py: -------------------------------------------------------------------------------- 1 | import collections 2 | 3 | # Keep indexes of good candidates in deque d. 4 | # The indexes in d are from the current window, they're increasing, 5 | # and their corresponding nums are decreasing. 6 | # Then the first deque element is the index of the largest window value. 7 | 8 | # For each index i: 9 | 10 | # 1. Pop (from the end) indexes of smaller elements (they'll be useless). 11 | # 2. Append the current index. 12 | # 3. Pop (from the front) the index i - k, if it's still in the deque 13 | # (it falls out of the window). 14 | # 4. If our window has reached size k, 15 | # append the current window maximum to the output. 16 | 17 | 18 | def max_sliding_window(nums, k): 19 | d = collections.deque() 20 | out = [] 21 | for i, n in enumerate(nums): 22 | while d and nums[d[-1]] < n: 23 | d.pop() 24 | d += i, 25 | if d[0] == i - k: 26 | d.popleft() 27 | if i >= k - 1: 28 | out += nums[d[0]], 29 | return out 30 | 31 | 32 | array = [1,3,-1,-3,5,3,6,7] 33 | 34 | print(max_sliding_window(array)) 35 | -------------------------------------------------------------------------------- /queue/moving_average.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | from collections import deque 3 | 4 | 5 | class MovingAverage(object): 6 | def __init__(self, size): 7 | """ 8 | Initialize your data structure here. 9 | :type size: int 10 | """ 11 | self.queue = deque(maxlen=size) 12 | 13 | def next(self, val): 14 | """ 15 | :type val: int 16 | :rtype: float 17 | """ 18 | self.queue.append(val) 19 | return sum(self.queue) / len(self.queue) 20 | 21 | 22 | # Given a stream of integers and a window size, 23 | # calculate the moving average of all integers in the sliding window. 24 | if __name__ == '__main__': 25 | m = MovingAverage(3) 26 | assert m.next(1) == 1 27 | assert m.next(10) == (1 + 10) / 2 28 | assert m.next(3) == (1 + 10 + 3) / 3 29 | assert m.next(5) == (10 + 3 + 5) / 3 30 | -------------------------------------------------------------------------------- /queue/queue.py: -------------------------------------------------------------------------------- 1 | # Queue Abstract Data Type (ADT) 2 | # * Queue() creates a new queue that is empty. 3 | # It needs no parameters and returns an empty queue. 4 | # * enqueue(item) adds a new item to the rear of the queue. 5 | # It needs the item and returns nothing. 6 | # * dequeue() removes the front item from the queue. 7 | # It needs no parameters and returns the item. The queue is modified. 8 | # * isEmpty() tests to see whether the queue is empty. 9 | # It needs no parameters and returns a boolean value. 10 | # * size() returns the number of items in the queue. 11 | # It needs no parameters and returns an integer. 12 | 13 | class AbstractQueue: 14 | def __init__(self): 15 | self.top = 0 16 | 17 | def isEmpty(self): 18 | return self.top == 0 19 | 20 | def __len__(self): 21 | return self.top 22 | 23 | def __str__(self): 24 | result = '------\n' 25 | for element in self: 26 | result += str(element) + '\n' 27 | return result[:-1] + '\n------' 28 | 29 | class ArrayQueue(AbstractStack): 30 | def __init__(self, size=10): 31 | """ 32 | Initialize python List with size of 10 or user given input. 33 | Python List type is a dynamic array, so we have to restrict its 34 | dynamic nature to make it work like a static array. 35 | """ 36 | AbstractStack.__init__(self) 37 | self.array = [None] * size 38 | self.front = 0 39 | self.rear = 0 40 | 41 | def enqueue(self, value): 42 | if self.top == len(self.array): 43 | self.expand() 44 | self.array[self.top] = value 45 | self.top += 1 46 | 47 | def dequeue(self): 48 | if self.isEmpty(): 49 | raise IndexError("stack is empty") 50 | value = self.array[self.top - 1] 51 | self.array[self.top - 1] = None 52 | self.top -= 1 53 | return value 54 | 55 | def expand(self): 56 | """ 57 | expands size of the array. 58 | Time Complexity: O(n) 59 | """ 60 | new_array = [None] * len(self.array) * 2 # double the size of the array 61 | for i, element in enumerate(self.array): 62 | new_array[i] = element 63 | self.array = new_array 64 | 65 | def __iter__(self): 66 | probe = self.top - 1 67 | while True: 68 | if probe < 0: 69 | raise StopIteration 70 | yield self.array[probe] 71 | probe -= 1 72 | 73 | class QueueNode(object): 74 | def __init__(self, value): 75 | self.value = value 76 | self.next = None 77 | 78 | class LinkedListQueue(AbstractStack): 79 | def __init__(self): 80 | AbstractQueue.__init__(self) 81 | self.front = None 82 | self.rear = None 83 | 84 | def enqueue(self, value): 85 | node = QueueNode(value) 86 | if not front: 87 | self.front = node 88 | self.rear = node 89 | else: 90 | self.rear.next = node 91 | self.rear = node 92 | self.top += 1 93 | 94 | def dequeue(self): 95 | if self.isEmpty(): 96 | raise IndexError("Queue is empty") 97 | value = self.front.value 98 | if self.front is self.rear: 99 | self.rear = None 100 | self.front = self.front.next 101 | self.top -= 1 102 | return value 103 | 104 | def __iter__(self): 105 | probe = self.head 106 | while True: 107 | if probe is None: 108 | raise StopIteration 109 | yield probe.value 110 | probe = probe.next 111 | 112 | class HeapPriorityQueue(AbstractStack): 113 | def __init__(self): 114 | pass 115 | -------------------------------------------------------------------------------- /queue/reconstruct_queue.py: -------------------------------------------------------------------------------- 1 | # Suppose you have a random list of people standing in a queue. 2 | # Each person is described by a pair of integers (h, k), 3 | # where h is the height of the person and k is the number of people 4 | # in front of this person who have a height greater than or equal to h. 5 | # Write an algorithm to reconstruct the queue. 6 | 7 | # Note: 8 | # The number of people is less than 1,100. 9 | 10 | # Example 11 | 12 | # Input: 13 | # [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] 14 | 15 | # Output: 16 | # [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]] 17 | 18 | def reconstruct_queue(people): 19 | """ 20 | :type people: List[List[int]] 21 | :rtype: List[List[int]] 22 | """ 23 | queue = [] 24 | people.sort(key=lambda x: (-x[0], x[1])) 25 | for h, k in people: 26 | queue.insert(k, (h, k)) 27 | return queue 28 | 29 | 30 | -------------------------------------------------------------------------------- /queue/zigzagiterator.py: -------------------------------------------------------------------------------- 1 | class ZigZagIterator: 2 | def __init__(self, v1, v2): 3 | """ 4 | Initialize your data structure here. 5 | :type v1: List[int] 6 | :type v2: List[int] 7 | """ 8 | self.queue=[_ for _ in (v1,v2) if _] 9 | print(self.queue) 10 | 11 | def next(self): 12 | """ 13 | :rtype: int 14 | """ 15 | v=self.queue.pop(0) 16 | ret=v.pop(0) 17 | if v: self.queue.append(v) 18 | return ret 19 | 20 | def has_next(self): 21 | """ 22 | :rtype: bool 23 | """ 24 | if self.queue: return True 25 | return False 26 | 27 | l1 = [1, 2] 28 | l2 = [3, 4, 5, 6] 29 | it = ZigZagIterator(l1, l2) 30 | while it.has_next(): 31 | print(it.next()) 32 | -------------------------------------------------------------------------------- /search/binary_search.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def binary_search(array, query): 4 | lo, hi = 0, len(array) - 1 5 | while lo <= hi: 6 | mid = lo + (hi - lo) // 2 7 | val = array[mid] 8 | if val == query: 9 | return mid 10 | elif val < query: 11 | lo = mid + 1 12 | else: 13 | hi = mid - 1 14 | return None 15 | 16 | array = [1,2,3,3,3,3,4,4,4,4,5,6] 17 | print(array) 18 | print("-----SEARCH-----") 19 | print("found: ", 5, " in index:" , binary_search(array, 5)) 20 | print("-----SEARCH-----") 21 | print("found: ", 6, " in index:" , binary_search(array, 6)) 22 | print("-----SEARCH-----") 23 | print("found: ", 7, " in index:" , binary_search(array, 7)) 24 | print("-----SEARCH-----") 25 | print("found: ", -1, " in index:" , binary_search(array, -1)) 26 | print("-----SEARCH-----") 27 | -------------------------------------------------------------------------------- /search/count_elem.py: -------------------------------------------------------------------------------- 1 | def count_elem(array, query): 2 | def first_occurance(array, query): 3 | lo, hi = 0, len(array) -1 4 | while lo <= hi: 5 | mid = lo + (hi - lo) // 2 6 | if (array[mid] == query and mid == 0) or \ 7 | (array[mid] == query and array[mid-1] < query): 8 | return mid 9 | elif (array[mid] <= query): 10 | lo = mid + 1 11 | else: 12 | hi = mid - 1 13 | def last_occurance(array, query): 14 | lo, hi = 0, len(array) -1 15 | while lo <= hi: 16 | mid = lo + (hi - lo) // 2 17 | if (array[mid] == query and mid == len(array) - 1) or \ 18 | (array[mid] == query and array[mid+1] > query): 19 | return mid 20 | elif (array[mid] <= query): 21 | lo = mid + 1 22 | else: 23 | hi = mid - 1 24 | 25 | first = first_occurance(array, query) 26 | last = last_occurance(array, query) 27 | if first is None or last is None: 28 | return None 29 | return last - first + 1 30 | 31 | 32 | 33 | array = [1,2,3,3,3,3,4,4,4,4,5,6,6,6] 34 | print(array) 35 | print("-----COUNT-----") 36 | query = 3 37 | print("count: ", query, " :" , count_elem(array, query)) 38 | print("-----COUNT-----") 39 | query = 5 40 | print("count: ", query, " :" , count_elem(array, query)) 41 | print("-----COUNT-----") 42 | query = 7 43 | print("count: ", query, " :" , count_elem(array, query)) 44 | print("-----COUNT-----") 45 | query = 1 46 | print("count: ", query, " :" , count_elem(array, query)) 47 | print("-----COUNT-----") 48 | query = -1 49 | print("count: ", query, " :" , count_elem(array, query)) 50 | print("-----COUNT-----") 51 | query = 9 52 | print("count: ", query, " :" , count_elem(array, query)) 53 | -------------------------------------------------------------------------------- /search/first_occurance.py: -------------------------------------------------------------------------------- 1 | def firstOccurance(array, query): 2 | lo, hi = 0, len(array) - 1 3 | while lo <= hi: 4 | mid = lo + (hi-lo) // 2 5 | print("lo: ", lo, " hi: ", hi, " mid: ", mid) 6 | if (mid == 0 and array[mid] == query) or \ 7 | (array[mid] == query and array[mid-1] < query): 8 | return mid 9 | elif array[mid] <= query: 10 | lo = mid + 1 11 | else: 12 | hi = mid - 1 13 | 14 | array = [1,2,3,3,3,3,4,4,4,4,5,6,6,6] 15 | print(array) 16 | print("-----SEARCH-----") 17 | query = 3 18 | print("found first: ", query, " in index:" , firstOccurance(array, query)) 19 | print("-----SEARCH-----") 20 | query = 5 21 | print("found first: ", query, " in index:" , firstOccurance(array, query)) 22 | print("-----SEARCH-----") 23 | query = 7 24 | print("found first: ", query, " in index:" , firstOccurance(array, query)) 25 | print("-----SEARCH-----") 26 | query = 1 27 | print("found first: ", query, " in index:" , firstOccurance(array, query)) 28 | print("-----SEARCH-----") 29 | query = -1 30 | print("found first: ", query, " in index:" , firstOccurance(array, query)) 31 | print("-----SEARCH-----") 32 | query = 9 33 | print("found first: ", query, " in index:" , firstOccurance(array, query)) 34 | -------------------------------------------------------------------------------- /search/last_occurance.py: -------------------------------------------------------------------------------- 1 | def lastOccurance(array, query): 2 | lo, hi = 0, len(array) - 1 3 | while lo <= hi: 4 | mid = lo + (hi - lo) // 2 5 | if (array[mid] == query and mid == len(array)-1) or \ 6 | (array[mid] == query and array[mid+1] > query): 7 | return mid 8 | elif (array[mid] <= query): 9 | lo = mid + 1 10 | else: 11 | hi = mid - 1 12 | 13 | 14 | array = [1,2,3,3,3,3,4,4,4,4,5,6,6,6] 15 | print(array) 16 | print("-----SEARCH-----") 17 | query = 3 18 | print("found last: ", query, " in index:" , lastOccurance(array, query)) 19 | print("-----SEARCH-----") 20 | query = 5 21 | print("found last: ", query, " in index:" , lastOccurance(array, query)) 22 | print("-----SEARCH-----") 23 | query = 7 24 | print("found last: ", query, " in index:" , lastOccurance(array, query)) 25 | print("-----SEARCH-----") 26 | query = 1 27 | print("found last: ", query, " in index:" , lastOccurance(array, query)) 28 | print("-----SEARCH-----") 29 | query = -1 30 | print("found last: ", query, " in index:" , lastOccurance(array, query)) 31 | print("-----SEARCH-----") 32 | query = 9 33 | print("found last: ", query, " in index:" , lastOccurance(array, query)) 34 | print("-----SEARCH-----") 35 | query = 6 36 | print("found last: ", query, " in index:" , lastOccurance(array, query)) 37 | -------------------------------------------------------------------------------- /set/randomized_set.py: -------------------------------------------------------------------------------- 1 | """ 2 | Design a data structure that supports all following operations 3 | in average O(1) time. 4 | 5 | insert(val): Inserts an item val to the set if not already present. 6 | remove(val): Removes an item val from the set if present. 7 | get_random: Returns a random element from current set of elements. 8 | Each element must have the same probability of being returned. 9 | """ 10 | 11 | 12 | class RandomizedSet(): 13 | """ 14 | idea: 15 | shit 16 | """ 17 | def __init__(self): 18 | pass 19 | 20 | def insert(self, val): 21 | pass 22 | 23 | def remove(self, val): 24 | pass 25 | 26 | def get_random(self): 27 | pass 28 | 29 | 30 | if __name__ == "__main__": 31 | rset = RandomizedSet() 32 | rset.insert(1) 33 | rset.insert(2) 34 | rset.insert(3) 35 | 36 | rset.remove(2) 37 | 38 | print(rset.get_random()) 39 | print(rset.get_random()) 40 | print(rset.get_random()) 41 | -------------------------------------------------------------------------------- /sort/insertion_sort.py: -------------------------------------------------------------------------------- 1 | def insertion_sort(arr): 2 | """ Insertion Sort 3 | Complexity: O(n^2) 4 | """ 5 | for i in xrange(len(arr)): 6 | cursor = arr[i] 7 | pos = i 8 | while pos > 0 and arr[pos-1] > cursor: 9 | # Swap the number down the list 10 | arr[pos] = arr[pos-1] 11 | pos = pos-1 12 | # Break and do the final swap 13 | arr[pos] = cursor 14 | return arr 15 | -------------------------------------------------------------------------------- /sort/meeting_rooms.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of meeting time intervals consisting of 3 | start and end times [[s1,e1],[s2,e2],...] (si < ei), 4 | determine if a person could attend all meetings. 5 | 6 | For example, 7 | Given [[0, 30],[5, 10],[15, 20]], 8 | return false. 9 | """ 10 | 11 | 12 | def can_attend_meetings(intervals): 13 | """ 14 | :type intervals: List[Interval] 15 | :rtype: bool 16 | """ 17 | intervals = sorted(intervals, key=lambda x: x.start) 18 | for i in range(1, len(intervals)): 19 | if intervals[i].start < intervals[i-1].end: 20 | return False 21 | return True 22 | -------------------------------------------------------------------------------- /sort/merge_sort.py: -------------------------------------------------------------------------------- 1 | def merge_sort(arr): 2 | """ Merge Sort 3 | Complexity: O(n log(n)) 4 | """ 5 | # Our recursive base case 6 | if len(arr)<= 1: 7 | return arr 8 | mid = len(arr)/2 9 | # Perform merge_sort recursively on both halves 10 | left, right = merge_sort(arr[mid:]), merge_sort(arr[:mid]) 11 | 12 | # Merge each side together 13 | return merge(left, right) 14 | 15 | def merge(left, right): 16 | """ Merge helper 17 | Complexity: O(n) 18 | """ 19 | arr = [] 20 | left_cursor, right_cursor = 0,0 21 | while left_cursor < len(left) and right_cursor < len(right): 22 | # Sort each one and place into the result 23 | if left[left_cursor] <= right[right_cursor]: 24 | arr.append(left[left_cursor]) 25 | left_cursor+=1 26 | else: 27 | arr.append(right[right_cursor]) 28 | right_cursor+=1 29 | # Add the left overs if there's any left to the result 30 | if left: 31 | arr.extend(left[left_cursor:]) 32 | if right: 33 | arr.extend(right[right_cursor:]) 34 | return arr 35 | 36 | array = [1,5, 7,4,3,2,1,9,0,10,43,64] 37 | print(array) 38 | print(merge_sort(array, 0, len(array)-1)) 39 | print(array) 40 | -------------------------------------------------------------------------------- /sort/quick_sort.py: -------------------------------------------------------------------------------- 1 | def quick_sort(arr, first, last): 2 | """ Quicksort 3 | Complexity: best O(n) avg O(n log(n)), worst O(N^2) 4 | """ 5 | if first < last: 6 | pos = partition(arr, first, last) 7 | print(arr[first:pos-1], arr[pos+1:last]) 8 | # Start our two recursive calls 9 | quick_sort(arr, first, pos-1) 10 | quick_sort(arr, pos+1, last) 11 | 12 | def partition(arr, first, last): 13 | wall = first 14 | for pos in range(first, last): 15 | if arr[pos] < arr[last]: # last is the pivot 16 | arr[pos], arr[wall] = arr[wall], arr[pos] 17 | wall += 1 18 | arr[wall], arr[last] = arr[last], arr[wall] 19 | print(wall) 20 | return wall 21 | 22 | array = [1,5,65,23,57,1232,-1,-5,-2,242,100,4,423,2,564,9,0,10,43,64] 23 | print(array) 24 | quick_sort(array, 0, len(array)-1) 25 | print(array) 26 | -------------------------------------------------------------------------------- /sort/selection_sort.py: -------------------------------------------------------------------------------- 1 | 2 | def selection_sort(arr): 3 | """ Selection Sort 4 | Complexity: O(n^2) 5 | """ 6 | for i in xrange(len(arr)): 7 | minimum = i 8 | for j in xrange(i+1, len(arr)): 9 | # "Select" the correct value 10 | if arr[j] < arr[minimum]: 11 | minimum = j 12 | # Using a pythonic swap 13 | arr[minimum], arr[i] = arr[i], arr[minimum] 14 | return arr 15 | 16 | 17 | -------------------------------------------------------------------------------- /sort/sort_colors.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array with n objects colored red, 3 | white or blue, sort them so that objects of the same color 4 | are adjacent, with the colors in the order red, white and blue. 5 | 6 | Here, we will use the integers 0, 1, and 2 to represent 7 | the color red, white, and blue respectively. 8 | 9 | Note: 10 | You are not suppose to use the library's sort function for this problem. 11 | """ 12 | 13 | 14 | def sort_colors(nums): 15 | i = j = 0 16 | for k in range(len(nums)): 17 | v = nums[k] 18 | nums[k] = 2 19 | if v < 2: 20 | nums[j] = 1 21 | j += 1 22 | if v == 0: 23 | nums[i] = 0 24 | i += 1 25 | 26 | 27 | if __name__ == "__main__": 28 | nums = [0,1,1,1,2,2,2,1,1,1,0,0,0,0,1,1,1,0,0,2,2] 29 | sort_colors(nums) 30 | print(nums) 31 | -------------------------------------------------------------------------------- /sort/topsort.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a list of system packages, 3 | some packages cannot be installed until the other packages are installed. 4 | Provide a valid sequence to install all of the packages. 5 | 6 | e.g. 7 | a relies on b 8 | b relies on c 9 | 10 | then a valid sequence is [c, b, a] 11 | """ 12 | 13 | depGraph = { 14 | 15 | "a" : [ "b" ], 16 | "b" : [ "c" ], 17 | "c" : [ 'e'], 18 | 'e' : [ ], 19 | "d" : [ ], 20 | "f" : ["e" , "d"] 21 | } 22 | 23 | 24 | given = [ "b", "c", "a", "d", "e", "f" ] 25 | 26 | def retDeps(visited, start): 27 | queue = [] 28 | out = [] 29 | queue.append(start) 30 | while queue: 31 | newNode = queue.pop(0) 32 | if newNode not in visited: 33 | visited.add(newNode) 34 | for child in depGraph[newNode]: 35 | queue.append(child) 36 | out.append(child) 37 | out.append(start) 38 | return out 39 | 40 | 41 | def retDepGraph(): 42 | visited = set() 43 | out = [] 44 | # visited.add(given[0]) 45 | for pac in given: 46 | if pac in visited: 47 | continue 48 | visited.add(pac) 49 | #out.append(pac) 50 | if pac in depGraph: 51 | # find all children 52 | for child in depGraph[pac]: 53 | if child in visited: 54 | continue 55 | out.extend(retDeps(visited, child)) 56 | out.append(pac) 57 | print(out) 58 | retDepGraph() 59 | -------------------------------------------------------------------------------- /sort/wiggle_sort.py: -------------------------------------------------------------------------------- 1 | 2 | def wiggle_sort(nums): 3 | for i in range(len(nums)): 4 | if (i % 2 == 1) == (nums[i-1] > nums[i]): 5 | nums[i-1], nums[i] = nums[i], nums[i-1] 6 | 7 | if __name__ == "__main__": 8 | array = [3, 5, 2, 1, 6, 4] 9 | 10 | print(array) 11 | wiggle_sort(array) 12 | print(array) 13 | 14 | 15 | -------------------------------------------------------------------------------- /stack/__init__.py: -------------------------------------------------------------------------------- 1 | from .stack import * 2 | -------------------------------------------------------------------------------- /stack/longest_abs_path.py: -------------------------------------------------------------------------------- 1 | # def lengthLongestPath(input): 2 | # maxlen = 0 3 | # pathlen = {0: 0} 4 | # for line in input.splitlines(): 5 | # print("---------------") 6 | # print("line:", line) 7 | # name = line.strip('\t') 8 | # print("name:", name) 9 | # depth = len(line) - len(name) 10 | # print("depth:", depth) 11 | # if '.' in name: 12 | # maxlen = max(maxlen, pathlen[depth] + len(name)) 13 | # else: 14 | # pathlen[depth + 1] = pathlen[depth] + len(name) + 1 15 | # print("maxlen:", maxlen) 16 | # return maxlen 17 | 18 | # def lengthLongestPath(input): 19 | # paths = input.split("\n") 20 | # level = [0] * 10 21 | # maxLength = 0 22 | # for path in paths: 23 | # print("-------------") 24 | # levelIdx = path.rfind("\t") 25 | # print("Path: ", path) 26 | # print("path.rfind(\\t)", path.rfind("\t")) 27 | # print("levelIdx: ", levelIdx) 28 | # print("level: ", level) 29 | # level[levelIdx + 1] = level[levelIdx] + len(path) - levelIdx + 1 30 | # print("level: ", level) 31 | # if "." in path: 32 | # maxLength = max(maxLength, level[levelIdx+1] - 1) 33 | # print("maxlen: ", maxLength) 34 | # return maxLength 35 | 36 | def length_longest_path(input): 37 | """ 38 | :type input: str 39 | :rtype: int 40 | """ 41 | currlen, maxlen = 0, 0 # running length and max length 42 | stack = [] # keep track of the name length 43 | for s in input.split('\n'): 44 | print("---------") 45 | print(":", s) 46 | depth = s.count('\t') # the depth of current dir or file 47 | print("depth: ", depth) 48 | print("stack: ", stack) 49 | print("curlen: ", currlen) 50 | while len(stack) > depth: # go back to the correct depth 51 | currlen -= stack.pop() 52 | stack.append(len(s.strip('\t'))+1) # 1 is the length of '/' 53 | currlen += stack[-1] # increase current length 54 | print("stack: ", stack) 55 | print("curlen: ", currlen) 56 | if '.' in s: # update maxlen only when it is a file 57 | maxlen = max(maxlen, currlen-1) # -1 is to minus one '/' 58 | return maxlen 59 | 60 | st= "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdirectory1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext" 61 | st2 = "a\n\tb1\n\t\tf1.txt\n\taaaaa\n\t\tf2.txt" 62 | print("path:", st2) 63 | 64 | print("answer:", lengthLongestPath(st2)) 65 | 66 | -------------------------------------------------------------------------------- /stack/simplify_path.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an absolute path for a file (Unix-style), simplify it. 3 | 4 | For example, 5 | path = "/home/", => "/home" 6 | path = "/a/./b/../../c/", => "/c" 7 | 8 | * Did you consider the case where path = "/../"? 9 | In this case, you should return "/". 10 | * Another corner case is the path might contain multiple slashes '/' together, such as "/home//foo/". 11 | In this case, you should ignore redundant slashes and return "/home/foo". 12 | """ 13 | 14 | def simplify_path(path): 15 | """ 16 | :type path: str 17 | :rtype: str 18 | """ 19 | skip = set(['..','.','']) 20 | stack = [] 21 | paths = path.split('/') 22 | for tok in paths: 23 | if tok == '..': 24 | if stack: 25 | stack.pop() 26 | elif tok not in skip: 27 | stack.append(tok) 28 | return '/' +'/'.join(stack) 29 | 30 | p = '/my/name/is/..//keon' 31 | print(p) 32 | print(simplify_path(p)) 33 | -------------------------------------------------------------------------------- /stack/stack.py: -------------------------------------------------------------------------------- 1 | # Stack Abstract Data Type (ADT) 2 | # Stack() creates a new stack that is empty. 3 | # It needs no parameters and returns an empty stack. 4 | # push(item) adds a new item to the top of the stack. 5 | # It needs the item and returns nothing. 6 | # pop() removes the top item from the stack. 7 | # It needs no parameters and returns the item. The stack is modified. 8 | # peek() returns the top item from the stack but does not remove it. 9 | # It needs no parameters. The stack is not modified. 10 | # isEmpty() tests to see whether the stack is empty. 11 | # It needs no parameters and returns a boolean value. 12 | # size() returns the number of items on the stack. 13 | # It needs no parameters and returns an integer. 14 | 15 | class AbstractStack: 16 | def __init__(self): 17 | self.top = 0 18 | 19 | def isEmpty(self): 20 | return self.top == 0 21 | 22 | def __len__(self): 23 | return self.top 24 | 25 | def __str__(self): 26 | result = '------\n' 27 | for element in self: 28 | result += str(element) + '\n' 29 | return result[:-1] + '\n------' 30 | 31 | class ArrayStack(AbstractStack): 32 | def __init__(self, size=10): 33 | """ 34 | Initialize python List with size of 10 or user given input. 35 | Python List type is a dynamic array, so we have to restrict its 36 | dynamic nature to make it work like a static array. 37 | """ 38 | AbstractStack.__init__(self) 39 | self.array = [None] * size 40 | 41 | def push(self, value): 42 | if self.top == len(self.array): 43 | self.expand() 44 | self.array[self.top] = value 45 | self.top += 1 46 | 47 | def pop(self): 48 | if self.isEmpty(): 49 | raise IndexError("stack is empty") 50 | value = self.array[self.top - 1] 51 | self.array[self.top - 1] = None 52 | self.top -= 1 53 | return value 54 | 55 | def peek(self): 56 | if self.isEmpty(): 57 | raise IndexError("stack is empty") 58 | return self.array[self.top] 59 | 60 | def expand(self): 61 | """ 62 | expands size of the array. 63 | Time Complexity: O(n) 64 | """ 65 | newArray = [None] * len(self.array) * 2 # double the size of the array 66 | for i, element in enumerate(self.array): 67 | newArray[i] = element 68 | self.array = newArray 69 | 70 | def __iter__(self): 71 | probe = self.top - 1 72 | while True: 73 | if probe < 0: 74 | raise StopIteration 75 | yield self.array[probe] 76 | probe -= 1 77 | 78 | class StackNode(object): 79 | def __init__(self, value): 80 | self.value = value 81 | self.next = None 82 | 83 | class LinkedListStack(AbstractStack): 84 | def __init__(self): 85 | AbstractStack.__init__(self) 86 | self.head = None 87 | 88 | def push(self, value): 89 | node = StackNode(value) 90 | node.next = self.head 91 | self.head = node 92 | self.top += 1 93 | 94 | def pop(self): 95 | if self.isEmpty(): 96 | raise IndexError("stack is empty") 97 | value = self.head.value 98 | self.head = self.head.next 99 | self.top -= 1 100 | return value 101 | 102 | def peek(self): 103 | if self.isEmpty(): 104 | raise IndexError("stack is empty") 105 | return self.head.value 106 | 107 | def __iter__(self): 108 | probe = self.head 109 | while True: 110 | if probe is None: 111 | raise StopIteration 112 | yield probe.value 113 | probe = probe.next 114 | -------------------------------------------------------------------------------- /stack/valid_parenthesis.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string containing just the characters 3 | '(', ')', '{', '}', '[' and ']', 4 | determine if the input string is valid. 5 | 6 | The brackets must close in the correct order, 7 | "()" and "()[]{}" are all valid but "(]" and "([)]" are not. 8 | """ 9 | 10 | 11 | def is_valid(s:"str")->"bool": 12 | stack = [] 13 | dic = { ")":"(", 14 | "}":"{", 15 | "]":"["} 16 | for char in s: 17 | if char in dic.values(): 18 | stack.append(char) 19 | elif char in dic.keys(): 20 | if stack == []: 21 | return False 22 | s = stack.pop() 23 | if dic[char] != s: 24 | return False 25 | return stack == [] 26 | 27 | 28 | if __name__ == "__main__": 29 | paren = "[]" 30 | print(paren, is_valid(paren)) 31 | paren = "[]()[]" 32 | print(paren, is_valid(paren)) 33 | paren = "[[[]]" 34 | print(paren, is_valid(paren)) 35 | paren = "{([])}" 36 | print(paren, is_valid(paren)) 37 | paren = "(}" 38 | print(paren, is_valid(paren)) 39 | -------------------------------------------------------------------------------- /string/add_binary.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two binary strings, 3 | return their sum (also a binary string). 4 | 5 | For example, 6 | a = "11" 7 | b = "1" 8 | Return "100". 9 | """ 10 | 11 | 12 | def add_binary(a, b): 13 | s = "" 14 | c, i, j = 0, len(a)-1, len(b)-1 15 | zero = ord('0') 16 | while (i >= 0 or j >= 0 or c == 1): 17 | if (i >= 0): 18 | c += ord(a[i]) - zero 19 | i -= 1 20 | if (j >= 0): 21 | c += ord(b[j]) - zero 22 | j -= 1 23 | s = chr(c % 2 + zero) + s 24 | c /= 2 25 | return s 26 | -------------------------------------------------------------------------------- /string/breaking_bad.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an api which returns an array of chemical names and an array of chemical 3 | symbols, display the chemical names with their symbol surrounded by square 4 | brackets: 5 | 6 | Ex: 7 | Chemicals array: ['Amazon', 'Microsoft', 'Google'] 8 | Symbols: ['I', 'Am', 'cro', 'Na', 'le', 'abc'] 9 | 10 | Output: 11 | [Am]azon, Mi[cro]soft, Goog[le] 12 | 13 | If the chemical string matches more than one symbol, then choose the one with 14 | longest length. (ex. 'Microsoft' matches 'i' and 'cro') 15 | 16 | My solution: 17 | (I sorted the symbols array in descending order of length and ran loop over 18 | chemicals array to find a symbol match(using indexOf in javascript) which 19 | worked. But I din't make it through the interview, I am guessing my solution 20 | was O(n2) and they expected an efficient algorithm. 21 | """ 22 | 23 | chemicals = ['Amazon', 'Microsoft', 'Google'] 24 | symbols = ['I', 'Am', 'cro', 'le', 'abc'] 25 | 26 | def match_symbol(chemicals, symbols): 27 | import re 28 | combined = [] 29 | 30 | for s in symbols: 31 | for c in chemicals: 32 | r = re.search(s, c) 33 | if r: 34 | combined.append(re.sub(s, "[{}]".format(s), c)) 35 | 36 | return combined 37 | 38 | 39 | print match_symbol(chemicals, symbols) 40 | 41 | """ 42 | One approach is to use a Trie for the dictionary (the symbols), and then match 43 | brute force. The complexity will depend on the dictionary; 44 | if all are suffixes of the other, it will be n*m 45 | (where m is the size of the dictionary). For example, in Python: 46 | """ 47 | 48 | from functools import reduce 49 | 50 | class TrieNode: 51 | def __init__(self): 52 | self.c = dict() 53 | self.sym = None 54 | 55 | def bracket(words, symbols): 56 | root = TrieNode() 57 | for s in symbols: 58 | t = root 59 | for char in s: 60 | if char not in t.c: 61 | t.c[char] = TrieNode() 62 | t = t.c[char] 63 | t.sym = s 64 | result = dict() 65 | for word in words: 66 | i = 0 67 | symlist = list() 68 | while i < len(word): 69 | j, t = i, root 70 | while j < len(word) and word[j] in t.c: 71 | t = t.c[word[j]] 72 | if t.sym is not None: 73 | symlist.append((j+1-len(t.sym), j+1, t.sym)) 74 | j += 1 75 | i += 1 76 | if len(symlist) > 0: 77 | sym = reduce(lambda x, y: x if x[1]-x[0] >= y[1]-y[0] else y, symlist) 78 | result[word] = "{}[{}]{}".format(word[:sym[0]], sym[2], word[sym[1]:]) 79 | return tuple(word if word not in result else result[word] for word in words) 80 | 81 | bracket(['amazon', 'microsoft', 'google'], ['i', 'am', 'cro', 'na', 'le', 'abc']) 82 | >>> ('[am]azon', 'mi[cro]soft', 'goog[le]') 83 | -------------------------------------------------------------------------------- /string/decode_string.py: -------------------------------------------------------------------------------- 1 | # Given an encoded string, return it's decoded string. 2 | 3 | # The encoding rule is: k[encoded_string], where the encoded_string 4 | # inside the square brackets is being repeated exactly k times. 5 | # Note that k is guaranteed to be a positive integer. 6 | 7 | # You may assume that the input string is always valid; No extra white spaces, 8 | # square brackets are well-formed, etc. 9 | 10 | # Furthermore, you may assume that the original data does not contain any 11 | # digits and that digits are only for those repeat numbers, k. 12 | # For example, there won't be input like 3a or 2[4]. 13 | 14 | # Examples: 15 | 16 | # s = "3[a]2[bc]", return "aaabcbc". 17 | # s = "3[a2[c]]", return "accaccacc". 18 | # s = "2[abc]3[cd]ef", return "abcabccdcdcdef". 19 | 20 | def decode_string(s): 21 | """ 22 | :type s: str 23 | :rtype: str 24 | """ 25 | stack = []; cur_num = 0; cur_string = '' 26 | for c in s: 27 | if c == '[': 28 | stack.append((cur_string, cur_num)) 29 | cur_string = '' 30 | cur_num = 0 31 | elif c == ']': 32 | prev_string, num = stack.pop() 33 | cur_string = prev_string + num * cur_string 34 | elif c.isdigit(): 35 | cur_num = cur_num*10 + int(c) 36 | else: 37 | cur_string += c 38 | return cur_string 39 | 40 | a = "3[a]2[bc]" #"aaabcbc". 41 | b = "3[a2[c]]" #"accaccacc". 42 | 43 | print(decode_string(a)) 44 | print(decode_string(b)) 45 | -------------------------------------------------------------------------------- /string/encode_decode.py: -------------------------------------------------------------------------------- 1 | # Design an algorithm to encode a list of strings to a string. 2 | # The encoded string is then sent over the network and is decoded 3 | # back to the original list of strings. 4 | 5 | # Machine 1 (sender) has the function: 6 | 7 | # string encode(vector strs) { 8 | # // ... your code 9 | # return encoded_string; 10 | # } 11 | # Machine 2 (receiver) has the function: 12 | # vector decode(string s) { 13 | # //... your code 14 | # return strs; 15 | # } 16 | # So Machine 1 does: 17 | 18 | # string encoded_string = encode(strs); 19 | # and Machine 2 does: 20 | 21 | # vector strs2 = decode(encoded_string); 22 | # strs2 in Machine 2 should be the same as strs in Machine 1. 23 | 24 | # Implement the encode and decode methods. 25 | 26 | def encode(strs): 27 | """Encodes a list of strings to a single string. 28 | :type strs: List[str] 29 | :rtype: str 30 | """ 31 | res = '' 32 | for string in strs.split(): 33 | res += str(len(string)) + ":" + string 34 | return res 35 | 36 | def decode(s): 37 | """Decodes a single string to a list of strings. 38 | :type s: str 39 | :rtype: List[str] 40 | """ 41 | strs = [] 42 | i = 0 43 | while i < len(s): 44 | index = s.find(":", i) 45 | size = int(s[i:index]) 46 | strs.append(s[index+1: index+1+size]) 47 | i = index+1+size 48 | return strs 49 | 50 | strs = "keon is awesome" 51 | print(strs) 52 | enc = encode(strs) 53 | print(enc) 54 | dec = decode(enc) 55 | print(dec) 56 | -------------------------------------------------------------------------------- /string/group_anagrams.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of strings, group anagrams together. 3 | 4 | For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"], 5 | Return: 6 | 7 | [ 8 | ["ate", "eat","tea"], 9 | ["nat","tan"], 10 | ["bat"] 11 | ] 12 | """ 13 | 14 | 15 | class Solution(object): 16 | def groupAnagrams(self, strs): 17 | d = {} 18 | ans = [] 19 | k = 0 20 | for str in strs: 21 | sstr = ''.join(sorted(str)) 22 | if sstr not in d: 23 | d[sstr] = k 24 | k = k+1 25 | ans.append([]) 26 | ans[-1].append(str) 27 | else: 28 | ans[d[sstr]].append(str) 29 | return ans 30 | -------------------------------------------------------------------------------- /string/int_to_roman.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer, convert it to a roman numeral. 3 | Input is guaranteed to be within the range from 1 to 3999. 4 | """ 5 | 6 | def int_to_roman(num): 7 | """ 8 | :type num: int 9 | :rtype: str 10 | """ 11 | M = ["", "M", "MM", "MMM"]; 12 | C = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"]; 13 | X = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"]; 14 | I = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]; 15 | return M[num//1000] + C[(num%1000)//100] + X[(num%100)//10] + I[num%10]; 16 | 17 | print(int_to_roman(644)) 18 | -------------------------------------------------------------------------------- /string/is_palindrome.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string, determine if it is a palindrome, 3 | considering only alphanumeric characters and ignoring cases. 4 | 5 | For example, 6 | "A man, a plan, a canal: Panama" is a palindrome. 7 | "race a car" is not a palindrome. 8 | 9 | Note: 10 | Have you consider that the string might be empty? 11 | This is a good question to ask during an interview. 12 | 13 | For the purpose of this problem, 14 | we define empty string as valid palindrome. 15 | """ 16 | 17 | 18 | def is_palindrome(s): 19 | """ 20 | :type s: str 21 | :rtype: bool 22 | """ 23 | i = 0 24 | j = len(s)-1 25 | while i < j: 26 | while i < j and not s[i].isalnum(): 27 | i += 1 28 | while i < j and not s[j].isalnum(): 29 | j -= 1 30 | if s[i].lower() != s[j].lower(): 31 | return False 32 | i, j = i+1, j-1 33 | return True 34 | -------------------------------------------------------------------------------- /string/license_number.py: -------------------------------------------------------------------------------- 1 | 2 | def license_number(key, K): 3 | res, alnum = [], [] 4 | for char in key: 5 | if char != "-": 6 | alnum.append(char) 7 | for i, char in enumerate(reversed(alnum)): 8 | res.append(char) 9 | if (i+1) % K == 0 and i != len(alnum)-1: 10 | res.append("-") 11 | return "".join(res[::-1]) 12 | 13 | 14 | print(license_number("a-bc-dfd-df", 1), 1) 15 | print(license_number("a-bc-dfd-df", 2), 2) 16 | print(license_number("a-bc-dfd-df", 3), 3) 17 | print(license_number("a-bc-dfd-df", 4), 4) 18 | print(license_number("a-bc-dfd-df", 5), 5) 19 | 20 | -------------------------------------------------------------------------------- /string/make_sentence.py: -------------------------------------------------------------------------------- 1 | """ 2 | For a given string and dictionary, how many sentences can you make from the 3 | string, such that all the words are contained in the dictionary. 4 | 5 | eg: for given string -> "appletablet" 6 | "apple", "tablet" 7 | "applet", "able", "t" 8 | "apple", "table", "t" 9 | "app", "let", "able", "t" 10 | 11 | "applet", {app, let, apple, t, applet} => 3 12 | "thing", {"thing"} -> 1 13 | """ 14 | 15 | count = 0 16 | 17 | def make_sentence(str_piece, dictionarys): 18 | global count 19 | if len(str_piece) == 0: 20 | return True 21 | for i in range(0, len(str_piece)): 22 | prefix, suffix = str_piece[0:i], str_piece[i:] 23 | if ((prefix in dictionarys and suffix in dictionarys) 24 | or (prefix in dictionarys 25 | and make_sentence(suffix, dictionarys))): 26 | count += 1 27 | return True 28 | 29 | 30 | if __name__ == "__main__": 31 | dictionarys = ["", "app", "let", "t", "apple", "applet"] 32 | word = "applet" 33 | make_sentence(word, dictionarys) 34 | print count -------------------------------------------------------------------------------- /string/multiply_strings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two non-negative integers num1 and num2 represented as strings, 3 | return the product of num1 and num2. 4 | 5 | Note: 6 | 7 | The length of both num1 and num2 is < 110. 8 | Both num1 and num2 contains only digits 0-9. 9 | Both num1 and num2 does not contain any leading zero. 10 | You must not use any built-in BigInteger library or convert 11 | the inputs to integer directly. 12 | """ 13 | 14 | 15 | def multiply(num1:"str", num2:"str")->"str": 16 | carry = 1 17 | interm = [] 18 | zero = ord('0') 19 | i_pos = 1 20 | for i in reversed(num1): 21 | j_pos = 1 22 | add = 0 23 | for j in reversed(num2): 24 | mult = (ord(i)-zero) * (ord(j)-zero) * j_pos * i_pos 25 | j_pos *= 10 26 | add += mult 27 | i_pos *= 10 28 | interm.append(add) 29 | return str(sum(interm)) 30 | 31 | 32 | if __name__ == "__main__": 33 | print(multiply("1", "23")) 34 | print(multiply("23", "23")) 35 | print(multiply("100", "23")) 36 | print(multiply("100", "10000")) 37 | -------------------------------------------------------------------------------- /string/one_edit_distance.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two strings S and T, determine if they are both one edit distance apart. 3 | """ 4 | 5 | 6 | def is_one_edit(s, t): 7 | """ 8 | :type s: str 9 | :type t: str 10 | :rtype: bool 11 | """ 12 | if len(s) > len(t): 13 | return is_one_edit(t, s) 14 | if len(t) - len(s) > 1 or t == s: 15 | return False 16 | for i in range(len(s)): 17 | if s[i] != t[i]: 18 | return s[i+1:] == t[i+1:] or s[i:] == t[i+1:] 19 | return True 20 | 21 | 22 | def is_one_edit2(s, t): 23 | l1, l2 = len(s), len(t) 24 | if l1 > l2: 25 | return is_one_edit2(t, s) 26 | if len(t) - len(s) > 1 or t == s: 27 | return False 28 | for i in range(len(s)): 29 | if s[i] != t[i]: 30 | if l1 == l2: 31 | s = s[:i]+t[i]+s[i+1:] # modify 32 | else: 33 | s = s[:i]+t[i]+s[i:] # insertion 34 | break 35 | return s == t or s == t[:-1] 36 | -------------------------------------------------------------------------------- /string/rabin_karp.py: -------------------------------------------------------------------------------- 1 | # Following program is the python implementation of 2 | # Rabin Karp Algorithm 3 | 4 | class RollingHash: 5 | def __init__(self, text, sizeWord): 6 | self.text = text 7 | self.hash = 0 8 | self.sizeWord = sizeWord 9 | 10 | for i in range(0, sizeWord): 11 | #ord maps the character to a number 12 | #subtract out the ASCII value of "a" to start the indexing at zero 13 | self.hash += (ord(self.text[i]) - ord("a")+1)*(26**(sizeWord - i -1)) 14 | 15 | #start index of current window 16 | self.window_start = 0 17 | #end of index window 18 | self.window_end = sizeWord 19 | 20 | def move_window(self): 21 | if self.window_end <= len(self.text) - 1: 22 | #remove left letter from hash value 23 | self.hash -= (ord(self.text[self.window_start]) - ord("a")+1)*26**(self.sizeWord-1) 24 | self.hash *= 26 25 | self.hash += ord(self.text[self.window_end])- ord("a")+1 26 | self.window_start += 1 27 | self.window_end += 1 28 | 29 | def window_text(self): 30 | return self.text[self.window_start:self.window_end] 31 | 32 | def rabin_karp(word, text): 33 | if word == "" or text == "": 34 | return None 35 | if len(word) > len(text): 36 | return None 37 | 38 | rolling_hash = RollingHash(text, len(word)) 39 | word_hash = RollingHash(word, len(word)) 40 | #word_hash.move_window() 41 | 42 | for i in range(len(text) - len(word) + 1): 43 | if rolling_hash.hash == word_hash.hash: 44 | if rolling_hash.window_text() == word: 45 | return i 46 | rolling_hash.move_window() 47 | return None 48 | 49 | -------------------------------------------------------------------------------- /string/reverse_string.py: -------------------------------------------------------------------------------- 1 | def recursive(s): 2 | l = len(s) 3 | if l < 2: 4 | return s 5 | return recursive(s[l//2:]) + recursive(s[:l//2]) 6 | 7 | s = "hello there" 8 | print(recursive(s)) 9 | 10 | def iterative(s): 11 | r = list(s) 12 | i, j = 0, len(s) - 1 13 | while i < j: 14 | r[i], r[j] = r[j], r[i] 15 | i += 1 16 | j -= 1 17 | return "".join(r) 18 | 19 | print(iterative(s)) 20 | 21 | def pythonic(s): 22 | r = list(reversed(s)) 23 | return "".join(r) 24 | 25 | print(pythonic(s)) 26 | -------------------------------------------------------------------------------- /string/reverse_vowel.py: -------------------------------------------------------------------------------- 1 | 2 | def reverse_vowel(s): 3 | vowels = "AEIOUaeiou" 4 | i, j = 0, len(s)-1 5 | s = list(s) 6 | while i < j: 7 | while i < j and s[i] not in vowels: 8 | i += 1 9 | while i < j and s[j] not in vowels: 10 | j -= 1 11 | s[i], s[j] = s[j], s[i] 12 | i, j = i + 1, j - 1 13 | return "".join(s) 14 | 15 | test = "hello" 16 | print(test) 17 | print(reverse_vowel(test)) 18 | -------------------------------------------------------------------------------- /string/reverse_words.py: -------------------------------------------------------------------------------- 1 | 2 | def reverse(array, i, j): 3 | while i < j: 4 | array[i], array[j] = array[j], array[i] 5 | i += 1 6 | j -= 1 7 | 8 | def reverse_words(string): 9 | arr = list(string) 10 | n = len(arr) 11 | reverse(arr, 0, n-1) 12 | 13 | start = None 14 | for i in range(n): 15 | if arr[i] == " ": 16 | if start is not None: 17 | reverse(arr, start, i-1) 18 | start = None 19 | elif i == n-1: 20 | if start is not None: 21 | reverse(arr, start, i) 22 | else: 23 | if start is None: 24 | start = i 25 | return "".join(arr) 26 | 27 | 28 | if __name__ == "__main__": 29 | test = "I am keon kim and I like pizza" 30 | print(test) 31 | print(reverse_words(test)) 32 | -------------------------------------------------------------------------------- /string/roman_to_int.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a roman numeral, convert it to an integer. 3 | Input is guaranteed to be within the range from 1 to 3999. 4 | """ 5 | 6 | 7 | def roman_to_int(s:"str")->"int": 8 | number = 0 9 | roman = {'M':1000, 'D':500, 'C': 100, 'L':50, 'X':10, 'V':5, 'I':1} 10 | for i in range(len(s)-1): 11 | if roman[s[i]] < roman[s[i+1]]: 12 | number -= roman[s[i]] 13 | else: 14 | number += roman[s[i]] 15 | return number + roman[s[-1]] 16 | 17 | 18 | if __name__ == "__main__": 19 | roman = "DCXXI" 20 | print(roman_to_int(roman)) 21 | -------------------------------------------------------------------------------- /string/word_squares.py: -------------------------------------------------------------------------------- 1 | # Given a set of words (without duplicates), 2 | # find all word squares you can build from them. 3 | 4 | # A sequence of words forms a valid word square 5 | # if the kth row and column read the exact same string, 6 | # where 0 ≤ k < max(numRows, numColumns). 7 | 8 | # For example, the word sequence ["ball","area","lead","lady"] forms 9 | # a word square because each word reads the same both horizontally 10 | # and vertically. 11 | 12 | # b a l l 13 | # a r e a 14 | # l e a d 15 | # l a d y 16 | # Note: 17 | # There are at least 1 and at most 1000 words. 18 | # All words will have the exact same length. 19 | # Word length is at least 1 and at most 5. 20 | # Each word contains only lowercase English alphabet a-z. 21 | 22 | # Example 1: 23 | 24 | # Input: 25 | # ["area","lead","wall","lady","ball"] 26 | 27 | # Output: 28 | # [ 29 | # [ "wall", 30 | # "area", 31 | # "lead", 32 | # "lady" 33 | # ], 34 | # [ "ball", 35 | # "area", 36 | # "lead", 37 | # "lady" 38 | # ] 39 | # ] 40 | 41 | # Explanation: 42 | # The output consists of two word squares. The order of output does not matter 43 | # (just the order of words in each word square matters). 44 | 45 | import collections 46 | 47 | def word_squares(words): 48 | n = len(words[0]) 49 | fulls = collections.defaultdict(list) 50 | for word in words: 51 | for i in range(n): 52 | fulls[word[:i]].append(word) 53 | 54 | def build(square): 55 | if len(square) == n: 56 | squares.append(square) 57 | return 58 | prefix = "" 59 | for k in range(len(square)): 60 | prefix += square[k][len(square)] 61 | for word in fulls[prefix]: 62 | build(square + [word]) 63 | squares = [] 64 | for word in words: 65 | build([word]) 66 | return squares 67 | 68 | dic =["area","lead","wall","lady","ball"] 69 | print(word_squares(dic)) 70 | 71 | -------------------------------------------------------------------------------- /tmp/temporary.md: -------------------------------------------------------------------------------- 1 | Given input which is a vector of (user name, log-in time, log-out time), 2 | output time series which will have number of users logged in at each given 3 | time slot in the input, output should only contain time slots which are given 4 | in input for example if the input is "September", 1.2, 4.5), 5 | ("June", 3.1, 6.7), ("August", 8.9, 10.3) output should contain only 6 | 1.2, 3.1, 4.5, 3.1, 6.7, 8.9, 10.3 7 | Example: /* [ ("September", 1.2, 4.5), ("June", 3.1, 6.7), ("August", 8.9, 10.3) ] => 8 | [(1.2, 1), (3.1, 2), (4.5, 1), (6.7, 0), (8.9, 1), (10.3, 0)] */ 9 | 10 | 11 | • Sweeping line method 12 | § record the time instance and it type: log in, log out 13 | § Sort the time instances. Keep a variable to record the number of logged in users, number 14 | § For a time instance, 15 | □ if it is log-in type, number++, print 16 | else number--, print 17 | 18 | 19 | 1. Constant time random access hash implementation 20 | 21 | 2. Efficient elevator API 22 | 23 | 3. Ransom note 24 | 25 | 4. Median of k unsorted arrays 26 | 27 | 5. Design of a task scheduler 28 | 29 | 6. Custom comparator 30 | -------------------------------------------------------------------------------- /tree/Segment_Tree/segment_tree.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Segment_tree creates a segment tree with a given array and function, 3 | allowing queries to be done later in log(N) time 4 | function takes 2 values and returns a same type value 5 | ''' 6 | class segment_tree: 7 | def __init__(self,arr,function): 8 | self.segment = [0 for x in range(3*len(arr)+3)] 9 | self.arr = arr 10 | self.fn = function 11 | self.maketree(0,0,len(arr)-1) 12 | 13 | def maketree(self,i,l,r): 14 | if l==r: 15 | self.segment[i] = self.arr[l] 16 | elif lR or rR or l>r: 23 | return None 24 | if L>=l and R<=r: 25 | return self.segment[i] 26 | val1 = self.__query(2*i+1,L,int((L+R)/2),l,r) 27 | val2 = self.__query(2*i+2,int((L+R+2)/2),R,l,r) 28 | print(L,R," returned ",val1,val2) 29 | if val1 != None: 30 | if val2 != None: 31 | return self.fn(val1,val2) 32 | return val1 33 | return val2 34 | 35 | 36 | def query(self,L,R): 37 | return self.__query(0,0,len(self.arr)-1,L,R) 38 | 39 | ''' 40 | Example - 41 | mytree = segment_tree([2,4,5,3,4],max) 42 | mytree.query(2,4) 43 | mytree.query(0,3) ... 44 | 45 | mytree = segment_tree([4,5,2,3,4,43,3],sum) 46 | mytree.query(1,8) 47 | ... 48 | 49 | ''' 50 | -------------------------------------------------------------------------------- /tree/binary_tree_paths.py: -------------------------------------------------------------------------------- 1 | def binaryTreePaths(root): 2 | res = [] 3 | if not root: 4 | return res 5 | DFS(res, root, str(root.val)) 6 | return res 7 | 8 | def DFS(res, root, cur): 9 | if not root.left and not root.right: 10 | res.append(cur) 11 | if root.left: 12 | DFS(res, root.left, cur+'->'+str(root.left.val)) 13 | if root.right: 14 | DFS(res, root.right, cur+'->'+str(root.right.val)) 15 | -------------------------------------------------------------------------------- /tree/bintree2list.py: -------------------------------------------------------------------------------- 1 | class Node(): 2 | def __init__(self, val = 0): 3 | self.val = val 4 | self.left = None 5 | self.right = None 6 | 7 | def bintree2list(root): 8 | """ 9 | type root: root class 10 | """ 11 | if not root: 12 | return root 13 | root = bintree2list_util(root) 14 | while root.left: 15 | root = root.left 16 | return root 17 | 18 | def bintree2list_util(root): 19 | if not root: 20 | return root 21 | if root.left: 22 | left = bintree2list_util(root.left) 23 | while left.right: 24 | left = left.right 25 | left.right = root 26 | root.left = left 27 | if root.right: 28 | right = bintree2list_util(root.right) 29 | while right.left: 30 | right = right.left 31 | right.left = root 32 | root.right = right 33 | return root 34 | 35 | def print_tree(root): 36 | while root: 37 | print(root.val) 38 | root = root.right 39 | 40 | tree = Node(10) 41 | tree.left = Node(12) 42 | tree.right = Node(15) 43 | tree.left.left = Node(25) 44 | tree.left.left.right = Node(100) 45 | tree.left.right = Node(30) 46 | tree.right.left = Node(36) 47 | 48 | head = bintree2list(tree) 49 | print_tree(head) 50 | -------------------------------------------------------------------------------- /tree/bst/BSTIterator.py: -------------------------------------------------------------------------------- 1 | 2 | class BSTIterator: 3 | def __init__(self, root): 4 | self.stack = [] 5 | while root: 6 | self.stack.append(root) 7 | root = root.left 8 | 9 | def has_next(self): 10 | return bool(self.stack) 11 | 12 | def next(self): 13 | node = stack.pop() 14 | tmp = node 15 | if tmp.right: 16 | tmp = tmp.right 17 | while tmp: 18 | self.stack.append(tmp) 19 | tmp = tmp.left 20 | return node.val 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tree/bst/array2bst.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array where elements are sorted in ascending order, 3 | convert it to a height balanced BST. 4 | """ 5 | # class TreeNode(object): 6 | # def __init__(self, x): 7 | # self.val = x 8 | # self.left = None 9 | # self.right = None 10 | 11 | 12 | def array2bst(nums): 13 | if not nums: 14 | return None 15 | mid = len(nums)//2 16 | node = Node(nums[mid]) 17 | node.left = array2bst(nums[:mid]) 18 | node.right = array2bst(nums[mid+1:]) 19 | return node 20 | -------------------------------------------------------------------------------- /tree/bst/bst_closest_value.py: -------------------------------------------------------------------------------- 1 | # Given a non-empty binary search tree and a target value, 2 | # find the value in the BST that is closest to the target. 3 | 4 | # Note: 5 | # Given target value is a floating point. 6 | # You are guaranteed to have only one unique value in the BST 7 | # that is closest to the target. 8 | 9 | 10 | # Definition for a binary tree node. 11 | # class TreeNode(object): 12 | # def __init__(self, x): 13 | # self.val = x 14 | # self.left = None 15 | # self.right = None 16 | 17 | def closest_value(root, target): 18 | """ 19 | :type root: TreeNode 20 | :type target: float 21 | :rtype: int 22 | """ 23 | a = root.val 24 | kid = root.left if target < a else root.right 25 | if not kid: 26 | return a 27 | b = closest_value(kid, target) 28 | return min((a,b), key=lambda x: abs(target-x)) 29 | -------------------------------------------------------------------------------- /tree/bst/delete_node.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST. 3 | 4 | Basically, the deletion can be divided into two stages: 5 | 6 | Search for a node to remove. 7 | If the node is found, delete the node. 8 | Note: Time complexity should be O(height of tree). 9 | 10 | Example: 11 | 12 | root = [5,3,6,2,4,null,7] 13 | key = 3 14 | 15 | 5 16 | / \ 17 | 3 6 18 | / \ \ 19 | 2 4 7 20 | 21 | Given key to delete is 3. So we find the node with value 3 and delete it. 22 | 23 | One valid answer is [5,4,6,2,null,null,7], shown in the following BST. 24 | 25 | 5 26 | / \ 27 | 4 6 28 | / \ 29 | 2 7 30 | 31 | Another valid answer is [5,2,6,null,4,null,7]. 32 | 33 | 5 34 | / \ 35 | 2 6 36 | \ \ 37 | 4 7 38 | """ 39 | 40 | class Solution(object): 41 | def deleteNode(self, root, key): 42 | """ 43 | :type root: TreeNode 44 | :type key: int 45 | :rtype: TreeNode 46 | """ 47 | if not root: return None 48 | 49 | if root.val == key: 50 | if root.left: 51 | # Find the right most leaf of the left sub-tree 52 | left_right_most = root.left 53 | while left_right_most.right: 54 | left_right_most = left_right_most.right 55 | # Attach right child to the right of that leaf 56 | left_right_most.right = root.right 57 | # Return left child instead of root, a.k.a delete root 58 | return root.left 59 | else: 60 | return root.right 61 | # If left or right child got deleted, the returned root is the child of the deleted node. 62 | elif root.val > key: 63 | root.left = self.deleteNode(root.left, key) 64 | else: 65 | root.right = self.deleteNode(root.right, key) 66 | return root 67 | -------------------------------------------------------------------------------- /tree/bst/is_bst.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary tree, determine if it is a valid binary search tree (BST). 3 | 4 | Assume a BST is defined as follows: 5 | 6 | The left subtree of a node contains only nodes 7 | with keys less than the node's key. 8 | The right subtree of a node contains only nodes 9 | with keys greater than the node's key. 10 | Both the left and right subtrees must also be binary search trees. 11 | Example 1: 12 | 2 13 | / \ 14 | 1 3 15 | Binary tree [2,1,3], return true. 16 | Example 2: 17 | 1 18 | / \ 19 | 2 3 20 | Binary tree [1,2,3], return false. 21 | """ 22 | 23 | 24 | def is_BST(root): 25 | """ 26 | :type root: TreeNode 27 | :rtype: bool 28 | """ 29 | if not root: 30 | return True 31 | stack = [] 32 | pre = None 33 | while root and stack: 34 | while root: 35 | stack.append(root) 36 | root = root.left 37 | root = stack.pop() 38 | if pre and root.val <= pre.val: 39 | return False 40 | pre = root 41 | root = root.right 42 | return True 43 | -------------------------------------------------------------------------------- /tree/bst/kth_smallest.py: -------------------------------------------------------------------------------- 1 | class Node: 2 | 3 | def __init__(self, val, left=None, right=None): 4 | self.val = val 5 | self.left = left 6 | self.right = right 7 | 8 | 9 | def kth_smallest(root, k): 10 | stack = [] 11 | while root or stack: 12 | while root: 13 | stack.append(root) 14 | root = root.left 15 | root = stack.pop() 16 | k -= 1 17 | if k == 0: 18 | break 19 | root = root.right 20 | return root.val 21 | 22 | 23 | class Solution(object): 24 | def kthSmallest(self, root, k): 25 | """ 26 | :type root: TreeNode 27 | :type k: int 28 | :rtype: int 29 | """ 30 | count = [] 31 | self.helper(root, count) 32 | return count[k-1] 33 | 34 | def helper(self, node, count): 35 | if not node: 36 | return 37 | 38 | self.helper(node.left, count) 39 | count.append(node.val) 40 | self.helper(node.right, count) 41 | 42 | if __name__ == '__main__': 43 | n1 = Node(100) 44 | n2 = Node(50) 45 | n3 = Node(150) 46 | n4 = Node(25) 47 | n5 = Node(75) 48 | n6 = Node(125) 49 | n7 = Node(175) 50 | n1.left, n1.right = n2, n3 51 | n2.left, n2.right = n4, n5 52 | n3.left, n3.right = n6, n7 53 | print(kth_smallest(n1, 2)) 54 | print(Solution().kthSmallest(n1, 2)) 55 | -------------------------------------------------------------------------------- /tree/bst/lowest_common_ancestor.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary search tree (BST), 3 | find the lowest common ancestor (LCA) of two given nodes in the BST. 4 | 5 | According to the definition of LCA on Wikipedia: 6 | “The lowest common ancestor is defined between two 7 | nodes v and w as the lowest node in T that has both v and w 8 | as descendants (where we allow a node to be a descendant of itself).” 9 | 10 | _______6______ 11 | / \ 12 | ___2__ ___8__ 13 | / \ / \ 14 | 0 _4 7 9 15 | / \ 16 | 3 5 17 | 18 | For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. 19 | Another example is LCA of nodes 2 and 4 is 2, 20 | since a node can be a descendant of itself according to the LCA definition. 21 | """ 22 | 23 | 24 | def lowest_common_ancestor(root, p, q): 25 | """ 26 | :type root: Node 27 | :type p: Node 28 | :type q: Node 29 | :rtype: Node 30 | """ 31 | while root: 32 | if p.val > root.val < q.val: 33 | root = root.right 34 | elif p.val < root.val > q.val: 35 | root = root.left 36 | else: 37 | return root 38 | -------------------------------------------------------------------------------- /tree/bst/predecessor.py: -------------------------------------------------------------------------------- 1 | def predecessor(root, node): 2 | pred = None 3 | while root: 4 | if node.val > root.val: 5 | pred = root 6 | root = root.right 7 | else: 8 | root = root.left 9 | return pred 10 | -------------------------------------------------------------------------------- /tree/bst/serialize_deserialize.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def serialize(root): 4 | def build_string(node): 5 | if node: 6 | vals.append(str(node.val)) 7 | build_string(node.left) 8 | build_string(node.right) 9 | else: 10 | vals.append("#") 11 | vals = [] 12 | build_string(root) 13 | return " ".join(vals) 14 | 15 | 16 | def deserialize(data): 17 | def build_tree(): 18 | val = next(vals) 19 | if val == "#": 20 | return None 21 | node = TreeNode(int(val)) 22 | node.left = build_tree() 23 | node.right = build_tree() 24 | return node 25 | vals = iter(data.split()) 26 | return build_tree() 27 | -------------------------------------------------------------------------------- /tree/bst/successor.py: -------------------------------------------------------------------------------- 1 | def successor(root, node): 2 | succ = None 3 | while root: 4 | if node.val < root.val: 5 | succ = root 6 | root = root.left 7 | else: 8 | root = root.right 9 | return succ 10 | -------------------------------------------------------------------------------- /tree/bst/unique_bst.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given n, how many structurally unique BST's 3 | (binary search trees) that store values 1...n? 4 | 5 | For example, 6 | Given n = 3, there are a total of 5 unique BST's. 7 | 8 | 1 3 3 2 1 9 | \ / / / \ \ 10 | 3 2 1 1 3 2 11 | / / \ \ 12 | 2 1 2 3 13 | """ 14 | 15 | 16 | """ 17 | Taking 1~n as root respectively: 18 | 1 as root: # of trees = F(0) * F(n-1) // F(0) == 1 19 | 2 as root: # of trees = F(1) * F(n-2) 20 | 3 as root: # of trees = F(2) * F(n-3) 21 | ... 22 | n-1 as root: # of trees = F(n-2) * F(1) 23 | n as root: # of trees = F(n-1) * F(0) 24 | 25 | So, the formulation is: 26 | F(n) = F(0) * F(n-1) + F(1) * F(n-2) + F(2) * F(n-3) + ... + F(n-2) * F(1) + F(n-1) * F(0) 27 | """ 28 | 29 | def num_trees(n): 30 | """ 31 | :type n: int 32 | :rtype: int 33 | """ 34 | dp = [0] * (n+1) 35 | dp[0] = 1 36 | dp[1] = 1 37 | for i in range(2, n+1): 38 | for j in range(i+1): 39 | dp[i] += dp[i-j] * dp[j-1] 40 | return dp[-1] 41 | -------------------------------------------------------------------------------- /tree/deepest_left.py: -------------------------------------------------------------------------------- 1 | # Given a binary tree, find the deepest node 2 | # that is the left child of its parent node. 3 | 4 | # Example: 5 | 6 | # 1 7 | # / \ 8 | # 2 3 9 | # / \ \ 10 | # 4 5 6 11 | # \ 12 | # 7 13 | # should return 4. 14 | 15 | 16 | class Node: 17 | def __init__(self, val = None): 18 | self.left = None 19 | self.right = None 20 | self.val = val 21 | 22 | class DeepestLeft: 23 | def __init__(self): 24 | self.depth = 0 25 | self.Node = None 26 | 27 | def find_deepest_left(root, is_left, depth, res): 28 | if not root: 29 | return 30 | if is_left and depth > res.depth: 31 | res.depth = depth 32 | res.Node = root 33 | find_deepest_left(root.left, True, depth + 1, res) 34 | find_deepest_left(root.right, False, depth + 1, res) 35 | 36 | root = Node(1) 37 | root.left = Node(2) 38 | root.right = Node(3) 39 | root.left.left = Node(4) 40 | root.left.right = Node(5) 41 | root.right.right = Node(6) 42 | root.right.right.right = Node(7) 43 | 44 | res = DeepestLeft() 45 | find_deepest_left(root, True, 1, res) 46 | if res.Node: 47 | print(res.Node.val) 48 | -------------------------------------------------------------------------------- /tree/invert_tree.py: -------------------------------------------------------------------------------- 1 | # invert a binary tree 2 | 3 | def reverse(root): 4 | if not root: 5 | return 6 | root.left, root.right = root.right, root.left 7 | if root.left: 8 | reverse(root.left) 9 | if root.right: 10 | reverse(root.right) 11 | -------------------------------------------------------------------------------- /tree/is_balanced.py: -------------------------------------------------------------------------------- 1 | 2 | def is_balanced(root): 3 | """ 4 | O(N) solution 5 | """ 6 | return -1 != get_depth(root) 7 | 8 | def get_depth(root): 9 | """ 10 | return 0 if unbalanced else depth + 1 11 | """ 12 | if not root: 13 | return 0 14 | left = get_depth(root.left) 15 | right = get_depth(root.right) 16 | if abs(left-right) > 1: 17 | return -1 18 | return 1 + max(left, right) 19 | 20 | ################################ 21 | 22 | def is_balanced(root): 23 | """ 24 | O(N^2) solution 25 | """ 26 | left = max_height(root.left) 27 | right = max_height(root.right) 28 | return abs(left-right) <= 1 and is_balanced(root.left) and is_balanced(root.right) 29 | 30 | def max_height(root): 31 | if not root: 32 | return 0 33 | return max(max_height(root.left), max_height(root.right)) + 1 34 | -------------------------------------------------------------------------------- /tree/is_subtree.py: -------------------------------------------------------------------------------- 1 | # Given two binary trees s and t, check if t is a subtree of s. 2 | # A subtree of a tree t is a tree consisting of a node in t and 3 | # all of its descendants in t. 4 | 5 | # Example 1: 6 | 7 | # Given s: 8 | 9 | # 3 10 | # / \ 11 | # 4 5 12 | # / \ 13 | # 1 2 14 | 15 | # Given t: 16 | 17 | # 4 18 | # / \ 19 | # 1 2 20 | # Return true, because t is a subtree of s. 21 | 22 | # Example 2: 23 | 24 | # Given s: 25 | 26 | # 3 27 | # / \ 28 | # 4 5 29 | # / \ 30 | # 1 2 31 | # / 32 | # 0 33 | 34 | # Given t: 35 | 36 | # 3 37 | # / 38 | # 4 39 | # / \ 40 | # 1 2 41 | # Return false, because even though t is part of s, 42 | # it does not contain all descendants of t. 43 | 44 | # Follow up: 45 | # What if one tree is significantly lager than the other? 46 | 47 | 48 | def is_subtree(big, small): 49 | flag = False 50 | queue = collections.deque() 51 | queue.append(big) 52 | while queue: 53 | node = queue.popleft() 54 | if node.val == small.val: 55 | flag = comp(node, small) 56 | break 57 | else: 58 | queue.append(node.left) 59 | queue.append(node.right) 60 | return flag 61 | 62 | def comp(p, q): 63 | if not p and not q: 64 | return True 65 | if p and q: 66 | return p.val == q.val and comp(p.left,q.left) and comp(p.right, q.right) 67 | return False 68 | 69 | 70 | -------------------------------------------------------------------------------- /tree/is_symmetric.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary tree, check whether it is a mirror of 3 | itself (ie, symmetric around its center). 4 | 5 | For example, this binary tree [1,2,2,3,4,4,3] is symmetric: 6 | 7 | 1 8 | / \ 9 | 2 2 10 | / \ / \ 11 | 3 4 4 3 12 | But the following [1,2,2,null,3,null,3] is not: 13 | 1 14 | / \ 15 | 2 2 16 | \ \ 17 | 3 3 18 | Note: 19 | Bonus points if you could solve it both recursively and iteratively. 20 | """ 21 | 22 | # TC: O(b) SC: O(log n) 23 | def is_symmetric(root): 24 | if not root: 25 | return True 26 | return helper(root.left, root.right) 27 | 28 | 29 | def helper(p, q): 30 | if not p and not q: 31 | return True 32 | if not p or not q or q.val != p.val: 33 | return False 34 | return helper(p.left, q.right) and helper(p.right, q.left) 35 | 36 | 37 | def is_symmetric_iterative(root): 38 | if not root: 39 | return True 40 | stack = [[root.left, root.right]] 41 | while stack: 42 | left, right = stack.pop() # popleft 43 | if not left and not right: 44 | continue 45 | if not left or not right: 46 | return False 47 | if left.val == right.val: 48 | stack.append([left.left, right.right]) 49 | stack.append([left.right, right.right]) 50 | else: 51 | return False 52 | return True 53 | -------------------------------------------------------------------------------- /tree/longest_consecutive.py: -------------------------------------------------------------------------------- 1 | # Given a binary tree, find the length of the longest consecutive sequence path. 2 | 3 | # The path refers to any sequence of nodes from some starting node to any node 4 | # in the tree along the parent-child connections. 5 | # The longest consecutive path need to be from parent to child 6 | # (cannot be the reverse). 7 | 8 | # For example, 9 | # 1 10 | # \ 11 | # 3 12 | # / \ 13 | # 2 4 14 | # \ 15 | # 5 16 | # Longest consecutive sequence path is 3-4-5, so return 3. 17 | # 2 18 | # \ 19 | # 3 20 | # / 21 | # 2 22 | # / 23 | # 1 24 | 25 | 26 | maxlen = 0 27 | def longestConsecutive(root): 28 | """ 29 | :type root: TreeNode 30 | :rtype: int 31 | """ 32 | if not root: 33 | return 0 34 | DFS(root, 0, root.val) 35 | return maxlen 36 | 37 | def DFS(root, cur, target): 38 | if not root: return 39 | if root.val == target: 40 | cur += 1 41 | else: 42 | cur = 1 43 | maxlen = max(cur, maxlen) 44 | DFS(root.left, cur, root.val+1) 45 | DFS(root.right, cur, root.val+1) 46 | -------------------------------------------------------------------------------- /tree/lowest_common_ancestor.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary tree, find the lowest common ancestor 3 | (LCA) of two given nodes in the tree. 4 | 5 | According to the definition of LCA on Wikipedia: 6 | “The lowest common ancestor is defined between two nodes 7 | v and w as the lowest node in T that has both v and w as 8 | descendants 9 | (where we allow a node to be a descendant of itself).” 10 | 11 | _______3______ 12 | / \ 13 | ___5__ ___1__ 14 | / \ / \ 15 | 6 _2 0 8 16 | / \ 17 | 7 4 18 | For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3. 19 | Another example is LCA of nodes 5 and 4 is 5, 20 | since a node can be a descendant of itself according to the LCA definition. 21 | """ 22 | 23 | 24 | def LCA(root, p, q): 25 | """ 26 | :type root: TreeNode 27 | :type p: TreeNode 28 | :type q: TreeNode 29 | :rtype: TreeNode 30 | """ 31 | if not root or root is p or root is q: 32 | return root 33 | left = LCA(root.left, p, q) 34 | right = LCA(root.right, p, q) 35 | if left and right: 36 | return root 37 | return left if left else right 38 | -------------------------------------------------------------------------------- /tree/max_height.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary tree, find its maximum depth. 3 | 4 | The maximum depth is the number of nodes along the 5 | longest path from the root node down to the farthest leaf node. 6 | """ 7 | 8 | 9 | class Node(): 10 | def __init__(self, val = 0): 11 | self.val = val 12 | self.left = None 13 | self.right = None 14 | 15 | # def max_height(root): 16 | # if not root: 17 | # return 0 18 | # return max(maxDepth(root.left), maxDepth(root.right)) + 1 19 | 20 | # iterative 21 | def max_height(root): 22 | if not root: 23 | return 0 24 | height = 0 25 | queue = [root] 26 | while queue: 27 | height += 1 28 | level = [] 29 | while queue: 30 | node = queue.pop(0) 31 | if node.left: 32 | level.append(node.left) 33 | if node.right: 34 | level.append(node.right) 35 | queue = level 36 | return height 37 | 38 | def print_tree(root): 39 | if root: 40 | print(root.val) 41 | print_tree(root.left) 42 | print_tree(root.right) 43 | 44 | tree = Node(10) 45 | tree.left = Node(12) 46 | tree.right = Node(15) 47 | tree.left.left = Node(25) 48 | tree.left.left.right = Node(100) 49 | tree.left.right = Node(30) 50 | tree.right.left = Node(36) 51 | 52 | height = max_height(tree) 53 | print_tree(tree) 54 | print("height:", height) 55 | -------------------------------------------------------------------------------- /tree/max_path_sum.py: -------------------------------------------------------------------------------- 1 | 2 | maximum = float("-inf") 3 | 4 | def max_path_sum(root): 5 | helper(root) 6 | return maximum 7 | 8 | def helper(root): 9 | if not root: 10 | return 0 11 | left = helper(root.left) 12 | right = helper(root.right) 13 | maximum = max(maximum, left+right+root.val) 14 | return root.val + max(left, right) 15 | -------------------------------------------------------------------------------- /tree/min_height.py: -------------------------------------------------------------------------------- 1 | class Node(): 2 | def __init__(self, val = 0): 3 | self.val = val 4 | self.left = None 5 | self.right = None 6 | 7 | 8 | def minDepth(self, root): 9 | """ 10 | :type root: TreeNode 11 | :rtype: int 12 | """ 13 | if not root: 14 | return 0 15 | if not root.left or not root.right: 16 | return max(self.minDepth(root.left), self.minDepth(root.right))+1 17 | return min(self.minDepth(root.left), self.minDepth(root.right)) + 1 18 | 19 | 20 | # iterative 21 | def min_height(root): 22 | if not root: 23 | return 0 24 | height = 0 25 | level = [root] 26 | while level: 27 | height += 1 28 | new_level = [] 29 | for node in level: 30 | if not node.left and not node.right: 31 | return height 32 | if node.left: 33 | new_level.append(node.left) 34 | if node.right: 35 | new_level.append(node.right) 36 | level = new_level 37 | return height 38 | 39 | 40 | def print_tree(root): 41 | if root: 42 | print(root.val) 43 | print_tree(root.left) 44 | print_tree(root.right) 45 | 46 | tree = Node(10) 47 | tree.left = Node(12) 48 | tree.right = Node(15) 49 | tree.left.left = Node(25) 50 | tree.left.left.right = Node(100) 51 | tree.left.right = Node(30) 52 | tree.right.left = Node(36) 53 | 54 | height = min_height(tree) 55 | print_tree(tree) 56 | print("height:", height) 57 | -------------------------------------------------------------------------------- /tree/path_sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary tree and a sum, determine if the tree has a root-to-leaf 3 | path such that adding up all the values along the path equals the given sum. 4 | 5 | For example: 6 | Given the below binary tree and sum = 22, 7 | 5 8 | / \ 9 | 4 8 10 | / / \ 11 | 11 13 4 12 | / \ \ 13 | 7 2 1 14 | return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22. 15 | """ 16 | 17 | 18 | def has_path_sum(root, sum): 19 | """ 20 | :type root: TreeNode 21 | :type sum: int 22 | :rtype: bool 23 | """ 24 | if not root: 25 | return False 26 | if not root.left and not root.right and root.val == sum: 27 | return True 28 | sum -= root.val 29 | return has_path_sum(root.left, sum) or has_path_sum(root.right, sum) 30 | 31 | 32 | # DFS with stack 33 | def has_path_sum2(root, sum): 34 | if not root: 35 | return False 36 | stack = [(root, root.val)] 37 | while stack: 38 | node, val = stack.pop() 39 | if not node.left and not node.right: 40 | if val == sum: 41 | return True 42 | if node.left: 43 | stack.append((node.left, val+node.left.val)) 44 | if node.right: 45 | stack.append((node.right, val+node.right.val)) 46 | return False 47 | 48 | 49 | # BFS with queue 50 | def has_path_sum3(root, sum): 51 | if not root: 52 | return False 53 | queue = [(root, sum-root.val)] 54 | while queue: 55 | node, val = queue.pop(0) # popleft 56 | if not node.left and not node.right: 57 | if val == 0: 58 | return True 59 | if node.left: 60 | queue.append((node.left, val-node.left.val)) 61 | if node.right: 62 | queue.append((node.right, val-node.right.val)) 63 | return False 64 | -------------------------------------------------------------------------------- /tree/path_sum2.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary tree and a sum, find all root-to-leaf 3 | paths where each path's sum equals the given sum. 4 | 5 | For example: 6 | Given the below binary tree and sum = 22, 7 | 5 8 | / \ 9 | 4 8 10 | / / \ 11 | 11 13 4 12 | / \ / \ 13 | 7 2 5 1 14 | return 15 | [ 16 | [5,4,11,2], 17 | [5,8,4,5] 18 | ] 19 | """ 20 | 21 | 22 | def path_sum(root, sum): 23 | if not root: 24 | return [] 25 | res = [] 26 | DFS(root, sum, [], res) 27 | return res 28 | 29 | def DFS(root, sum, ls, res): 30 | if not root.left and not root.right and root.val == sum: 31 | ls.append(root.val) 32 | res.append(ls) 33 | if root.left: 34 | DFS(root.left, sum-root.val, ls+[root.val], res) 35 | if root.right: 36 | DFS(root.right, sum-root.val, ls+[root.val], res) 37 | 38 | 39 | # DFS with stack 40 | def path_sum2(root, s): 41 | if not root: 42 | return [] 43 | res = [] 44 | stack = [(root, [root.val])] 45 | while stack: 46 | node, ls = stack.pop() 47 | if not node.left and not node.right and sum(ls) == s: 48 | res.append(ls) 49 | if node.left: 50 | stack.append((node.left, ls+[node.left.val])) 51 | if node.right: 52 | stack.append((node.right, ls+[node.right.val])) 53 | return res 54 | 55 | 56 | # BFS with queue 57 | def path_sum3(root, sum): 58 | if not root: 59 | return [] 60 | res = [] 61 | queue = [(root, root.val, [root.val])] 62 | while queue: 63 | node, val, ls = queue.pop(0) # popleft 64 | if not node.left and not node.right and val == sum: 65 | res.append(ls) 66 | if node.left: 67 | queue.append((node.left, val+node.left.val, ls+[node.left.val])) 68 | if node.right: 69 | queue.append((node.right, val+node.right.val, ls+[node.right.val])) 70 | return res 71 | -------------------------------------------------------------------------------- /tree/pretty_print.py: -------------------------------------------------------------------------------- 1 | # a -> Adam -> Book -> 4 2 | # b -> Bill -> Computer -> 5 3 | # -> TV -> 6 4 | # Jill -> Sports -> 1 5 | # c -> Bill -> Sports -> 3 6 | # d -> Adam -> Computer -> 3 7 | # Quin -> Computer -> 3 8 | # e -> Quin -> Book -> 5 9 | # -> TV -> 2 10 | # f -> Adam -> Computer -> 7 11 | 12 | def treePrint(tree): 13 | for key in tree: 14 | print key, # comma prevents a newline character 15 | treeElem = tree[key] # multiple lookups is expensive, even amortized O(1)! 16 | for subElem in treeElem: 17 | print " -> ", subElem, 18 | if type(subElem) != str: # OP wants indenting after digits 19 | print "\n " # newline and a space to match indenting 20 | print "" # forces a newline 21 | -------------------------------------------------------------------------------- /tree/same_tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two binary trees, write a function to check 3 | if they are equal or not. 4 | 5 | Two binary trees are considered equal if they are 6 | structurally identical and the nodes have the same value. 7 | """ 8 | 9 | 10 | def isSameTree(p, q): 11 | if not p and not q: 12 | return True 13 | if p and q and p.val == q.val: 14 | return isSameTree(p.left, q.left) and isSameTree(p.right, q.right) 15 | return False 16 | 17 | # Time Complexity O(min(N,M)) 18 | # where N and M are the number of nodes for the trees. 19 | 20 | # Space Complexity O(min(height1, height2)) 21 | # levels of recursion is the mininum height between the two trees. 22 | -------------------------------------------------------------------------------- /tree/traversal/inorder.py: -------------------------------------------------------------------------------- 1 | class Node: 2 | 3 | def __init__(self, val, left=None, right=None): 4 | self.val = val 5 | self.left = left 6 | self.right = right 7 | 8 | 9 | def inorder(root): 10 | res = [] 11 | if not root: 12 | return res 13 | stack = [] 14 | while root or stack: 15 | while root: 16 | stack.append(root) 17 | root = root.left 18 | root = stack.pop() 19 | res.append(root.val) 20 | root = root.right 21 | return res 22 | 23 | if __name__ == '__main__': 24 | n1 = Node(100) 25 | n2 = Node(50) 26 | n3 = Node(150) 27 | n4 = Node(25) 28 | n5 = Node(75) 29 | n6 = Node(125) 30 | n7 = Node(175) 31 | n1.left, n1.right = n2, n3 32 | n2.left, n2.right = n4, n5 33 | n3.left, n3.right = n6, n7 34 | print(inorder(n1)) 35 | -------------------------------------------------------------------------------- /tree/traversal/level_order.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary tree, return the level order traversal of 3 | its nodes' values. (ie, from left to right, level by level). 4 | 5 | For example: 6 | Given binary tree [3,9,20,null,null,15,7], 7 | 3 8 | / \ 9 | 9 20 10 | / \ 11 | 15 7 12 | return its level order traversal as: 13 | [ 14 | [3], 15 | [9,20], 16 | [15,7] 17 | ] 18 | """ 19 | 20 | 21 | def level_order(root): 22 | ans = [] 23 | if not root: 24 | return ans 25 | level = [root] 26 | while level: 27 | current = [] 28 | new_level = [] 29 | for node in level: 30 | current.append(node.val) 31 | if node.left: 32 | new_level.append(node.left) 33 | if node.right: 34 | new_level.append(node.right) 35 | level = new_level 36 | ans.append(current) 37 | return ans 38 | -------------------------------------------------------------------------------- /tree/traversal/zigzag.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary tree, return the zigzag level order traversal 3 | of its nodes' values. 4 | (ie, from left to right, then right to left 5 | for the next level and alternate between). 6 | 7 | For example: 8 | Given binary tree [3,9,20,null,null,15,7], 9 | 3 10 | / \ 11 | 9 20 12 | / \ 13 | 15 7 14 | return its zigzag level order traversal as: 15 | [ 16 | [3], 17 | [20,9], 18 | [15,7] 19 | ] 20 | """ 21 | 22 | 23 | def zigzag_level(root): 24 | res = [] 25 | if not root: 26 | return res 27 | level = [root] 28 | flag = 1 29 | while level: 30 | current = [] 31 | new_level = [] 32 | for node in level: 33 | current.append(node.val) 34 | if node.left: 35 | new_level.append(node.left) 36 | if node.right: 37 | new_level.append(node.right) 38 | level = new_level 39 | res.append(current[::flag]) 40 | flag *= -1 41 | return res 42 | -------------------------------------------------------------------------------- /tree/tree.py: -------------------------------------------------------------------------------- 1 | class TreeNode: 2 | def __init__(self, val=0): 3 | self.val = val 4 | self.left = None 5 | self.right = None 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tree/trie/add_and_search.py: -------------------------------------------------------------------------------- 1 | """ 2 | We are asked to design an efficient data structure 3 | that allows us to add and search for words. 4 | The search can be a literal word or regular expression 5 | containing “.”, where “.” can be any letter. 6 | 7 | Example: 8 | addWord(“bad”) 9 | addWord(“dad”) 10 | addWord(“mad”) 11 | search(“pad”) -> false 12 | search(“bad”) -> true 13 | search(“.ad”) -> true 14 | search(“b..”) -> true 15 | """ 16 | import collections 17 | 18 | class TrieNode(object): 19 | def __init__(self, letter, is_terminal=False): 20 | self.children = dict() 21 | self.letter = letter 22 | self.is_terminal = is_terminal 23 | 24 | class WordDictionary(object): 25 | def __init__(self): 26 | self.root = TrieNode("") 27 | 28 | def addWord(self, word): 29 | cur = self.root 30 | for letter in word: 31 | if letter not in cur.children: 32 | cur.children[letter] = TrieNode(letter) 33 | cur = cur.children[letter] 34 | cur.is_terminal = True 35 | 36 | def search(self, word, node=None): 37 | cur = node 38 | if not cur: 39 | cur = self.root 40 | for i, letter in enumerate(word): 41 | # if dot 42 | if letter == ".": 43 | if i == len(word) - 1: # if last character 44 | for child in cur.children.itervalues(): 45 | if child.is_terminal: 46 | return True 47 | return False 48 | for child in cur.children.itervalues(): 49 | if self.search(word[i+1:], child) == True: 50 | return True 51 | return False 52 | # if letter 53 | if letter not in cur.children: 54 | return False 55 | cur = cur.children[letter] 56 | return cur.is_terminal 57 | 58 | class WordDictionary2(object): 59 | def __init__(self): 60 | self.word_dict = collections.defaultdict(list) 61 | 62 | 63 | def addWord(self, word): 64 | if word: 65 | self.word_dict[len(word)].append(word) 66 | 67 | def search(self, word): 68 | if not word: 69 | return False 70 | if '.' not in word: 71 | return word in self.word_dict[len(word)] 72 | for v in self.word_dict[len(word)]: 73 | # match xx.xx.x with yyyyyyy 74 | for i, ch in enumerate(word): 75 | if ch != v[i] and ch != '.': 76 | break 77 | else: 78 | return True 79 | return False 80 | -------------------------------------------------------------------------------- /tree/trie/trie.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement a trie with insert, search, and startsWith methods. 3 | 4 | Note: 5 | You may assume that all inputs are consist of lowercase letters a-z. 6 | """ 7 | class TrieNode: 8 | def __init__(self): 9 | self.children = collections.defaultdict(TrieNode) 10 | self.is_word = False 11 | 12 | class Trie: 13 | def __init__(self): 14 | self.root = TrieNode() 15 | 16 | def insert(self, word): 17 | current = self.root 18 | for letter in word: 19 | current = current.children[letter] 20 | current.is_word = True 21 | 22 | def search(self, word): 23 | current = self.root 24 | for letter in word: 25 | current = current.children.get(letter) 26 | if current is None: 27 | return False 28 | return current.is_word 29 | 30 | def startsWith(self, prefix): 31 | current = self.root 32 | for letter in prefix: 33 | current = current.children.get(letter) 34 | if current is None: 35 | return False 36 | return True 37 | 38 | -------------------------------------------------------------------------------- /union-find/count_islands.py: -------------------------------------------------------------------------------- 1 | """ 2 | A 2d grid map of m rows and n columns is initially filled with water. 3 | We may perform an addLand operation which turns the water at position 4 | (row, col) into a land. Given a list of positions to operate, 5 | count the number of islands after each addLand operation. 6 | An island is surrounded by water and is formed by connecting adjacent 7 | lands horizontally or vertically. 8 | You may assume all four edges of the grid are all surrounded by water. 9 | 10 | Given m = 3, n = 3, positions = [[0,0], [0,1], [1,2], [2,1]]. 11 | Initially, the 2d grid grid is filled with water. 12 | (Assume 0 represents water and 1 represents land). 13 | 14 | 0 0 0 15 | 0 0 0 16 | 0 0 0 17 | Operation #1: addLand(0, 0) turns the water at grid[0][0] into a land. 18 | 19 | 1 0 0 20 | 0 0 0 Number of islands = 1 21 | 0 0 0 22 | Operation #2: addLand(0, 1) turns the water at grid[0][1] into a land. 23 | 24 | 1 1 0 25 | 0 0 0 Number of islands = 1 26 | 0 0 0 27 | Operation #3: addLand(1, 2) turns the water at grid[1][2] into a land. 28 | 29 | 1 1 0 30 | 0 0 1 Number of islands = 2 31 | 0 0 0 32 | Operation #4: addLand(2, 1) turns the water at grid[2][1] into a land. 33 | 34 | 1 1 0 35 | 0 0 1 Number of islands = 3 36 | 0 1 0 37 | """ 38 | 39 | 40 | class Solution(object): 41 | def numIslands2(self, m, n, positions): 42 | ans = [] 43 | islands = Union() 44 | for p in map(tuple, positions): 45 | islands.add(p) 46 | for dp in (0, 1), (0, -1), (1, 0), (-1, 0): 47 | q = (p[0] + dp[0], p[1] + dp[1]) 48 | if q in islands.id: 49 | islands.unite(p, q) 50 | ans += [islands.count] 51 | return ans 52 | 53 | class Union(object): 54 | def __init__(self): 55 | self.id = {} 56 | self.sz = {} 57 | self.count = 0 58 | 59 | def add(self, p): 60 | self.id[p] = p 61 | self.sz[p] = 1 62 | self.count += 1 63 | 64 | def root(self, i): 65 | while i != self.id[i]: 66 | self.id[i] = self.id[self.id[i]] 67 | i = self.id[i] 68 | return i 69 | 70 | def unite(self, p, q): 71 | i, j = self.root(p), self.root(q) 72 | if i == j: 73 | return 74 | if self.sz[i] > self.sz[j]: 75 | i, j = j, i 76 | self.id[i] = j 77 | self.sz[j] += self.sz[i] 78 | self.count -= 1 79 | --------------------------------------------------------------------------------