├── .gitignore ├── valid_number.png ├── README.md ├── LinkedList.py ├── plus_one.py ├── single_number.py ├── gen_parentheses.py ├── sqrt.py ├── multiplication_of_nums.py ├── len_last_word.py ├── pow.py ├── search_insert_pos.py ├── anagrams.py ├── container_water.py ├── prime_num.py ├── permutation_seq.py ├── restore_ip_addr.py ├── valid_parentheses.py ├── balanced_binary_tree.py ├── palin_number.py ├── arithmetic_bitwise.py ├── recover_BST.py ├── BST2doubly_llist.py ├── longest_common_prefix.py ├── pascal_tri.py ├── permutation.py ├── candy.py ├── count_and_say.py ├── str_reorder_dist_apart.py ├── swap_nodes_pairs.py ├── search_range.py ├── first_missing_pos.py ├── simplify_path.py ├── max_subarray.py ├── sorted2BST.py ├── sum_root_to_leaf_num.py ├── rotate_images.py ├── zigzag_conversion.py ├── min_window_substr.py ├── wildcard_matching.py ├── partition_list.py ├── comb_sum.py ├── divide_two_nums.py ├── add_binary.py ├── grey_code.py ├── min_path_sum.py ├── triangle.py ├── valid_BST.py ├── word_search.py ├── strstr.py ├── edit_dist.py ├── longest_valid_parentheses.py ├── maximum_product_subarray.py ├── add_two_nums.py ├── set_matrix_zeros.py ├── longest_consec_seq.py ├── jump_game.py ├── copy_list_random_pointer.py ├── interleaving_str.py ├── same_tree.py ├── binary_tree_traversal.py ├── valid_number.py ├── distinct_subseq.py ├── binary_tree_path_sum.py ├── uniq_BST.py ├── path_sum.py ├── uniq_paths.py ├── int_to_roman.py ├── valid_sudoku.py ├── sort_colors.py ├── spiral_matrix.py ├── 3sum_closest.py ├── regex_match.py ├── insert_interval.py ├── search_rotated_sorted_arr.py ├── next_permutation.py ├── arithmetic_str.py ├── substr_concat_words.py ├── letter_comb_phone.py ├── merge_intervals.py ├── LCA.py ├── sym_tree.py ├── str_to_int.py ├── merge_lists.py ├── 3sum.py ├── max_rect.py ├── longest_substr_no_repeat.py ├── search_2D_matrix.py ├── sudoku_solver.py ├── n_queens.py ├── flat_tree_to_llist.py ├── decode_ways.py ├── surrounded_reg.py ├── popu_next_right_pointer.py ├── text_justify.py ├── subsets.py ├── tree_depth.py ├── palin_partition.py ├── trap_rain_water.py ├── largest_rectangle_under_hist.py ├── BinaryTree.py ├── word_break.py ├── reverse_sth.py ├── gas_station.py ├── longest_palin_substr.py └── best_time_buy_sell.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .xlsx 3 | .pyc 4 | *.*~ 5 | _*_.* 6 | 7 | -------------------------------------------------------------------------------- /valid_number.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilianweng/LeetcodePython/HEAD/valid_number.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Leetcode Practice in Python 2 | ============== 3 | This repository includes answers to Leetcode coding interview questions. 4 | 5 | ALl the problems please refer to http://oj.leetcode.com/problems/ 6 | 7 | The problem descriptions are also included in each python file. 8 | 9 | -------------------------------------------------------------------------------- /LinkedList.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | 5 | class Node(object): 6 | def __init__(self, value, next=None, prev=None): 7 | self.prev = prev 8 | self.next = next 9 | self.value = value 10 | 11 | def __str__(self): 12 | if self.next is None: 13 | return str(self.value) 14 | else: 15 | return '%d (%s)' % (self.value, str(self.next)) 16 | 17 | def __repr__(self): 18 | s = 'LinkedListNode Object (value='+str(self.value)+')' 19 | return s 20 | 21 | 22 | -------------------------------------------------------------------------------- /plus_one.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Plus one 4 | Given a number represented as an array of digits, plus one to the number. 5 | ''' 6 | from __future__ import division 7 | import random 8 | 9 | def plus_one(digits): 10 | print digits, '+ 1 =', 11 | carry = 1 12 | for i in reversed(xrange(len(digits))): 13 | x = digits[i] 14 | carry, x = divmod(x+carry, 10) 15 | digits[i] = x 16 | if carry > 0: digits.insert(0,carry) 17 | print digits 18 | return digits 19 | 20 | if __name__ == '__main__': 21 | plus_one([1,2,3,4]) 22 | plus_one([1,9,9]) 23 | plus_one([9,9,9]) 24 | plus_one([0]) 25 | 26 | 27 | -------------------------------------------------------------------------------- /single_number.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | 6 | ''' 7 | Leetcode: Single Number 8 | 9 | Given an array of integers, every element appears twice except for one. Find that single one. 10 | Note: Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory? 11 | ''' 12 | def func(): 13 | pass 14 | 15 | 16 | ''' 17 | Leetcode: Single Number II 18 | 19 | Given an array of integers, every element appears three times except for one. Find that single one. 20 | Note: Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory? 21 | 22 | 23 | ''' 24 | def func(): 25 | pass 26 | 27 | 28 | if __name__ == '__main__': 29 | func() 30 | 31 | 32 | -------------------------------------------------------------------------------- /gen_parentheses.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Generate Parentheses 4 | Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. For example, given n = 3, a solution set is: "((()))", "(()())", "(())()", "()(())", "()()()" 5 | ''' 6 | from __future__ import division 7 | import random 8 | 9 | def parentheses_combination(left, right): 10 | if left == 0 and right == 0: yield '' 11 | if left > 0: 12 | for p in parentheses_combination(left-1, right): 13 | yield '('+p 14 | if right > left: 15 | for p in parentheses_combination(left, right-1): 16 | yield ')'+p 17 | 18 | 19 | # Other ways? 20 | 21 | if __name__ == '__main__': 22 | for p in parentheses_combination(4,4): print p 23 | 24 | 25 | -------------------------------------------------------------------------------- /sqrt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Sqrt(x) 4 | Implement int sqrt(int x). 5 | Compute and return the square root of x. 6 | ''' 7 | from __future__ import division 8 | import random 9 | 10 | DIFF = 10**-10 11 | 12 | # Binary search 13 | def sqrt(x): 14 | from math import fabs 15 | if x == 0: return 0 16 | elif x < 0: return None 17 | elif x == 1: return 1 18 | elif x > 1: 19 | a = 1; b = x 20 | else: # x < 1 21 | a = 0; b = 1 22 | 23 | while a < b: 24 | mid = (a+b)/2 25 | if fabs(mid*mid-x) < DIFF: return mid 26 | elif x > mid*mid: a = mid 27 | else: b = mid 28 | return a 29 | 30 | 31 | if __name__ == '__main__': 32 | print sqrt(100) 33 | print sqrt(5) 34 | print sqrt(2) 35 | print sqrt(0.1) 36 | print sqrt(0.03435435) 37 | print sqrt(0.0001) 38 | 39 | 40 | -------------------------------------------------------------------------------- /multiplication_of_nums.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: There is an array A[N] of N numbers. You have to compose an array Output[N] such that Output[i] will be equal to multiplication of all the elements of A[N] except A[i]. Solve it without division operator and in O(n). 4 | 5 | For example Output[0] will be multiplication of A[1] to A[N-1] and Output[1] will be multiplication of A[0] and from A[2] to A[N-1]. 6 | http://leetcode.com/2010/04/multiplication-of-numbers.html 7 | ''' 8 | from __future__ import division 9 | import random 10 | 11 | 12 | def multi_of_nums(A): 13 | n = len(A) 14 | L = [1]*n 15 | R = [1]*n 16 | for i in range(n-1): 17 | L[i+1] = L[i]*A[i] 18 | for i in range(n-1,0,-1): 19 | R[i-1] = R[i]*A[i] 20 | ret = [L[i]*R[i] for i in range(n)] 21 | print ret 22 | return ret 23 | 24 | 25 | if __name__ == '__main__': 26 | multi_of_nums([4,3,2,1,2,3]) 27 | 28 | 29 | -------------------------------------------------------------------------------- /len_last_word.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Length of Last Word 4 | Given a string s consists of upper/lower-case alphabets and empty space characters ' ', return the length of last word in the string. 5 | If the last word does not exist, return 0. Note: A word is defined as a character sequence consists of non-space characters only. 6 | For example, Given s = "Hello World", return 5. 7 | ''' 8 | from __future__ import division 9 | import random 10 | 11 | def last_word(s): 12 | # upper/lower-case alphabets and empty space 13 | # remove spaces at the end 14 | while s and not s[-1].isalpha(): s = s[:-1] 15 | length = 0 16 | for i in reversed(xrange(len(s))): 17 | if s[i].isalpha(): length += 1 18 | else: return length 19 | return length 20 | 21 | if __name__ == '__main__': 22 | print last_word("Hello World") 23 | print last_word(" ") 24 | print last_word(" a a a ") 25 | 26 | 27 | -------------------------------------------------------------------------------- /pow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: pow(x,n) 4 | pow(x,n) = x^n 5 | ''' 6 | from __future__ import division 7 | import random 8 | 9 | # Divide and Conquer 10 | # remember that n can be < 0 11 | # O(logn) 12 | def pow(x, n): 13 | if n == 0: return 1 14 | elif n == 1: return x 15 | elif n > 1: 16 | half = pow(x, n//2) 17 | if n % 2 == 0: return half*half 18 | else: return half*half*x 19 | else: # n < 0 20 | return 1/pow(x, -n) 21 | 22 | 23 | def pow2(x,n): 24 | if n == 0: return 1 25 | if n == 1: return x 26 | m = -n if n < 0 else n 27 | ret = 1 28 | while m > 0: 29 | if m & 1: ret *= x 30 | # x^n --> (x^2)^(n/2) 31 | x *= x 32 | m >>= 1 33 | return 1/ret if n < 0 else ret 34 | 35 | if __name__ == '__main__': 36 | print pow2(10,2) 37 | print pow2(10,0) 38 | print pow2(5,3) 39 | print pow2(5,-3) 40 | print pow2(2,10) 41 | 42 | 43 | -------------------------------------------------------------------------------- /search_insert_pos.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Search Insert Position 4 | Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order. 5 | You may assume no duplicates in the array. 6 | Here are few examples. 7 | [1,3,5,6], 5 --> 2 8 | [1,3,5,6], 2 --> 1 9 | [1,3,5,6], 7 --> 4 10 | [1,3,5,6], 0 --> 0 11 | ''' 12 | from __future__ import division 13 | import random 14 | 15 | def search_insert_pos(L, val): 16 | l = 0; r = len(L)-1 17 | while l < r: 18 | mid = (l+r+1)//2 19 | if L[mid] == val: return mid 20 | elif L[mid] < val: l = mid+1 21 | else: r = mid-1 22 | return l if L[l] > val else l+1 23 | 24 | if __name__ == '__main__': 25 | print search_insert_pos([1,3,5,6], 5) 26 | print search_insert_pos([1,3,5,6], 2) 27 | print search_insert_pos([1,3,5,6], 7) 28 | print search_insert_pos([1,3,5,6], 0) 29 | 30 | 31 | -------------------------------------------------------------------------------- /anagrams.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Anagrams 4 | Given an array of strings, return all groups of strings that are anagrams. 5 | Note: All inputs will be in lower-case. 6 | ''' 7 | from __future__ import division 8 | import random 9 | 10 | ### Use permutation generator 11 | def anagrams_generator(s): 12 | if len(s) == 1: 13 | yield s 14 | else: 15 | for i in range(len(s)): 16 | elem = s[i] 17 | # keep one element away 18 | for a in anagrams_generator(s[:i] + s[i+1:]): 19 | for j in range(len(a)+1): 20 | # insert this element into any possible position 21 | yield a[:j] + elem + a[j:] 22 | 23 | def anagrams(s): 24 | print 'Anagrams of '+s+':', 25 | output = set([a for a in anagrams_generator(s)]) 26 | print list(output) 27 | 28 | 29 | ### Other solution? 30 | # Permutation with repetition? 31 | 32 | 33 | 34 | if __name__ == '__main__': 35 | anagrams('aab') 36 | anagrams('hello') 37 | 38 | 39 | -------------------------------------------------------------------------------- /container_water.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Container With Most Water 4 | Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water. 5 | Note: You may not slant the container. 6 | ''' 7 | from __future__ import division 8 | import random 9 | 10 | # Find i < j to maximize (j-i)*min{ai, aj}, see 2sum 11 | # O(n) 12 | def container_water(a): 13 | i, j = 0, len(a)-1 14 | water = 0 15 | water_i = water_j = None 16 | while i < j: 17 | cur = (j-i)* min(a[i], a[j]) 18 | if cur > water: water = cur; water_i = i; water_j = j 19 | if a[i] < a[j]: i += 1 20 | else: j -= 1 21 | print '(%d,%d): %d' % (water_i,water_j,water) 22 | return water 23 | 24 | 25 | if __name__ == '__main__': 26 | a = [2,1,3,2,4,5,2,3,1,4] 27 | print container_water(a) -------------------------------------------------------------------------------- /prime_num.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | from math import sqrt 6 | 7 | ''' 8 | Output all prime numbers up to a specified integer n. 9 | ''' 10 | # using The Sieve of Erantosthenes 11 | def prime_sieve(n): 12 | is_prime = dict((i,True) for i in range(2,n+1)) 13 | limit = int(sqrt(n)) 14 | for i in range(2, limit+1): 15 | for j in range(2, n//i+1): 16 | is_prime[i*j] = False 17 | ret = [n for n in is_prime if is_prime[n]] 18 | print ret 19 | return ret 20 | 21 | ''' 22 | Output first n prime numbers 23 | ''' 24 | def prime(n): 25 | primes = [2] 26 | num = 3 27 | while len(primes) < n: 28 | is_prime = True 29 | for p in primes: 30 | if num % p == 0: 31 | is_prime = False 32 | break 33 | if is_prime: 34 | primes.append(num) 35 | num += 1 36 | print primes 37 | return primes 38 | 39 | 40 | if __name__ == '__main__': 41 | prime_sieve(230) 42 | prime(50) 43 | 44 | 45 | -------------------------------------------------------------------------------- /permutation_seq.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Permutation Sequence 4 | The set [1,2,3,...,n] contains a total of n! unique permutations. 5 | By listing and labeling all of the permutations in order, 6 | We get the following sequence (ie, for n = 3): 7 | "123" 8 | "132" 9 | "213" 10 | "231" 11 | "312" 12 | "321" 13 | Given n and k, return the kth permutation sequence. 14 | Note: Given n will be between 1 and 9 inclusive. 15 | ''' 16 | from __future__ import division 17 | import random 18 | #from math import factorial 19 | 20 | # k = 0,1,...,(n!-1) 21 | def permu_seq(n, k): 22 | fact = 1 23 | for i in range(1,n+1): 24 | fact *= i 25 | if k >= fact: return "" 26 | 27 | digits = range(1,n+1) 28 | seq = [] 29 | while n > 0: 30 | fact = int(fact/n) 31 | i, k = divmod(k, fact) 32 | seq.append( digits[i] ) 33 | digits.pop(i) 34 | n -= 1 35 | print seq 36 | return "".join(map(str,seq)) 37 | 38 | 39 | if __name__ == '__main__': 40 | permu_seq(3,3) 41 | permu_seq(5,55) 42 | 43 | 44 | -------------------------------------------------------------------------------- /restore_ip_addr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Restore IP Addresses 4 | Given a string containing only digits, restore it by returning all possible valid IP address combinations. 5 | For example: 6 | Given "25525511135", 7 | return ["255.255.11.135", "255.255.111.35"]. (Order does not matter) 8 | ''' 9 | from __future__ import division 10 | import random 11 | 12 | 13 | # each digit between 0~255 14 | def gen_ip_addr(s, num_part): 15 | if num_part == 0 and len(s) == 0: yield [] 16 | elif num_part == 1 and 1 <= len(s) <= 3: yield [s] 17 | else: 18 | for l in range(1, min(3,len(s))+1): 19 | digit = s[:l] 20 | if int(digit) > 255: continue 21 | for p in gen_ip_addr(s[l:], num_part-1): 22 | yield [digit] + p 23 | 24 | 25 | def ip_addr(s): 26 | ips = [] 27 | for p in gen_ip_addr(s, 4): 28 | print '.'.join(p) 29 | ips.append('.'.join(p)) 30 | return ips 31 | 32 | 33 | if __name__ == '__main__': 34 | ip_addr("25525511135") 35 | ip_addr("1122211120") 36 | 37 | 38 | -------------------------------------------------------------------------------- /valid_parentheses.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Valid Parentheses 4 | Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. 5 | The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not. 6 | ''' 7 | from __future__ import division 8 | import random 9 | 10 | 11 | # Use stack; never push right parenthesis but only try to 12 | # match it with left ones in the stack 13 | def valid_parentheses(s): 14 | lefts = {'(':0, '{':1, '[':2} 15 | rights = {')':0, '}':1, ']':2} 16 | stack = [] 17 | for ch in s: 18 | if ch in lefts: 19 | stack.append(lefts[ch]) 20 | elif ch in rights: 21 | if not stack: return False 22 | if stack[-1] == rights[ch]: stack.pop() 23 | else: return False 24 | else: 25 | return False 26 | return True 27 | 28 | 29 | if __name__ == '__main__': 30 | print valid_parentheses('[{}[]((()))]') 31 | print valid_parentheses('[{[(((]))})]') 32 | 33 | 34 | -------------------------------------------------------------------------------- /balanced_binary_tree.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Balanced Binary Tree 4 | 5 | Given a binary tree, determine if it is height-balanced. 6 | For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1. 7 | ''' 8 | 9 | from __future__ import division 10 | import random 11 | from BinaryTree import Node, SampleTreeRoot 12 | 13 | 14 | # return, True/False (whether balanced), height of the tree 15 | import math 16 | def balanced_binary_tree(root): 17 | if not root: 18 | return True, 0 19 | if not root.left and not root.right: 20 | return True, 1 21 | 22 | balance_left, left = balanced_binary_tree(root.left) 23 | balance_right, right = balanced_binary_tree(root.right) 24 | is_balanced = (math.fabs(left-right) <=1 and balance_left and balance_right) 25 | tree_height = max(left, right) + 1 26 | return is_balanced, tree_height 27 | 28 | 29 | if __name__ == '__main__': 30 | 31 | root = SampleTreeRoot 32 | print root 33 | print balanced_binary_tree(root) 34 | 35 | 36 | -------------------------------------------------------------------------------- /palin_number.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Palindrome number 4 | 5 | Determine whether an integer is a palindrome. Do this without extra space. 6 | * Should be interesting if it is a float, but it is hard to determine the accuracy 7 | 8 | http://leetcode.com/2012/01/palindrome-number.html 9 | ''' 10 | from __future__ import division 11 | import math 12 | 13 | # number with k digit 14 | # 10**(k-1) <= num < 10**k 15 | def pali_num(num): 16 | print 'Check:', num, 17 | if num < 0: return False 18 | if num == 0: return True 19 | k = int(math.log10(num)) + 1 20 | base = 10**(k-1) 21 | while num > 0 and base > 1: 22 | # left-most digit? 23 | left = num // base 24 | num -= left*base 25 | base /= 100 26 | # right-most digit? 27 | right = num % 10 28 | num = num // 10 29 | if left != right: return False 30 | return True 31 | 32 | 33 | if __name__ == '__main__': 34 | print pali_num(12345) 35 | print pali_num(12321) 36 | print pali_num(123321) 37 | print pali_num(1236666321) 38 | print pali_num(-1) 39 | print pali_num(-0) 40 | print pali_num(0) 41 | -------------------------------------------------------------------------------- /arithmetic_bitwise.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Bitwise 4 | ''' 5 | from __future__ import division 6 | import random 7 | 8 | 9 | def add(a,b): 10 | if a == 0 or b == 0: 11 | return max(a,b) 12 | sum = a ^ b 13 | carry = (a & b) << 1 14 | return add(sum, carry) 15 | 16 | 17 | def sub(a,b): 18 | return add(a, ~b+1) 19 | 20 | 21 | def multiply(a,b): 22 | import math 23 | if b == 0: return 0 24 | elif b == 1: return a 25 | else: 26 | if b & 1 == 1: 27 | # add x + a 28 | x = multiply((a<<1), (b>>1)) 29 | while a!=0 and x!=0: 30 | sum = a^b 31 | carry = (a&b)<<1 32 | a = sum; x = carry 33 | return max(a,x) 34 | else: 35 | return multiply((a<<1), (b>>1)) 36 | 37 | 38 | def divide(a,b): 39 | ret = 0 40 | while a >= b: 41 | c = b; i = 0 42 | # double b in each loop 43 | while a >= c: 44 | a -= c 45 | c <<= 1 46 | ret += (1 << i) 47 | i += 1 48 | return ret 49 | 50 | 51 | if __name__ == '__main__': 52 | print add(11,4) 53 | print multiply(12,11) -------------------------------------------------------------------------------- /recover_BST.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Recover Binary Search Tree 4 | Two elements of a binary search tree (BST) are swapped by mistake. 5 | Recover the tree without changing its structure. 6 | Note: A solution using O(n) space is pretty straight forward. Could you devise a constant space solution? 7 | ''' 8 | from __future__ import division 9 | import random 10 | from BinaryTree import Node, BST 11 | 12 | def find_outliers(root, outliers): 13 | if root.left: 14 | if root.left.value <= root.value: 15 | find_outliers(root.left, outliers) 16 | else: 17 | outliers.append(root.left) 18 | if root.right: 19 | if root.right.value >= root.value: 20 | return find_outliers(root.right, outliers) 21 | else: 22 | outliers.append(root.right) 23 | 24 | 25 | # time ~ O(n), space ~ O(1) 26 | def recover_BST(root): 27 | print root 28 | outliers = [] 29 | find_outliers(root, outliers) 30 | x, y = outliers 31 | print x, y 32 | # swith them 33 | x.value, y.value = y.value, x.value 34 | print root 35 | 36 | 37 | if __name__ == '__main__': 38 | recover_BST(BST) 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /BST2doubly_llist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Convert Binary Search Tree (BST) to Sorted Doubly-Linked List 4 | ''' 5 | from __future__ import division 6 | import random 7 | from BinaryTree import * 8 | 9 | 10 | def get_tail(node): 11 | while node.right: 12 | node = node.right 13 | return node 14 | 15 | 16 | def convert(root): 17 | if not root: return None 18 | left_list = convert(root.left) 19 | right_list = convert(root.right) 20 | 21 | if left_list: 22 | tail = get_tail(left_list) 23 | tail.right = root 24 | root.left = tail 25 | 26 | if right_list: 27 | right_list.left = root 28 | root.right = right_list 29 | 30 | if left_list: return left_list 31 | else: return root 32 | 33 | 34 | if __name__ == '__main__': 35 | print BST 36 | head = convert(BST) 37 | 38 | # to right 39 | node = head 40 | while node.right: 41 | print node.value, '->', 42 | node = node.right 43 | print node.value 44 | 45 | # to right 46 | while node.left: 47 | print node.value, '<-', 48 | node = node.left 49 | print node.value 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /longest_common_prefix.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Longest Common Prefix 4 | Write a function to find the longest common prefix string amongst an array of strings. 5 | ''' 6 | from __future__ import division 7 | import random 8 | 9 | ### Solution#1: Build a trie tree: O(nm) 10 | 11 | 12 | ### Solution#2: Hash the first string as f, fl, flo, flow, flowe, flower, and initialize the max_prefix_len=5. 13 | # For every other string s, start checking the prefix with min{max_prefix_len, len(s)}. If match go to the next string; if not, remove the last character and re-compare. ~O(n+m) 14 | def longest_prefix(strings): 15 | first = strings[0] 16 | prefixs = set([first[:i] for i in range(len(first))]) 17 | max_prefix_len = len(first) 18 | i = 1 19 | while i < len(strings) and max_prefix_len > 0: 20 | s = strings[i] 21 | # Adjust the length 22 | l = min(len(s), max_prefix_len) 23 | s = s[:l] 24 | max_prefix_len = l 25 | while s not in prefixs: 26 | s = s[:-1] 27 | max_prefix_len -= 1 28 | i += 1 29 | return first[:max_prefix_len] 30 | 31 | 32 | if __name__ == '__main__': 33 | print longest_prefix(['hello','hell','heaven','heavy']) 34 | 35 | 36 | -------------------------------------------------------------------------------- /pascal_tri.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | 6 | 7 | ''' 8 | Leetcode: Pascal's Triangle 9 | Given numRows, generate the first numRows of Pascal's triangle. 10 | For example, given numRows = 5, 11 | Return 12 | [ 13 | [1], 14 | [1,1], 15 | [1,2,1], 16 | [1,3,3,1], 17 | [1,4,6,4,1] 18 | ]''' 19 | def pascal(n): 20 | if n == 0: return [] 21 | rows = [[1]] 22 | row = [1] 23 | for i in range(1,n): 24 | row = [1] + [row[j]+row[j+1] for j in range(len(row)-1)] + [1] 25 | rows.append(row) 26 | print '\n'.join(map(str,rows)) 27 | return rows 28 | 29 | 30 | ''' 31 | Leetcode: Pascal's Triangle II 32 | Given an index k, return the kth row of the Pascal's triangle. 33 | For example, given k = 3, return [1,3,3,1]. 34 | Note: Could you optimize your algorithm to use only O(k) extra space? 35 | ''' 36 | def pascal2(k): 37 | # k-th row: C(k,0), C(k,1), ..., C(k,k) 38 | # C(k,i+1) = C(k,i) * (k-i) / (i+1) 39 | row = [1] 40 | C = 1 41 | for i in range(k): 42 | C *= (k-i)/(i+1) 43 | row.append( int(C) ) 44 | print row 45 | return row 46 | 47 | 48 | if __name__ == '__main__': 49 | pascal(5) 50 | pascal2(4) 51 | 52 | 53 | -------------------------------------------------------------------------------- /permutation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | 6 | 7 | ''' 8 | Leetcode: Permutations 9 | Given a collection of numbers, return all possible permutations. 10 | For example, 11 | [1,2,3] have the following permutations: 12 | [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], and [3,2,1]. 13 | ''' 14 | 15 | ''' 16 | Leetcode: Permutations II 17 | Given a collection of numbers that might contain duplicates, return all possible unique permutations. 18 | For example, 19 | [1,1,2] have the following unique permutations: 20 | [1,1,2], [1,2,1], and [2,1,1] 21 | ''' 22 | 23 | def gen_permu(L): 24 | n = len(L) 25 | if n == 0: yield [] 26 | elif n == 1: yield L 27 | else: 28 | checked = set() # cache digit that has been put at this position 29 | for i in range(n): 30 | if L[i] in checked: continue 31 | checked.add(L[i]) 32 | for p in gen_permu(L[:i] + L[i+1:]): 33 | yield [L[i]] + p 34 | 35 | 36 | def permu(L): 37 | counter = 0 38 | for p in gen_permu(L): 39 | print p 40 | counter += 1 41 | print 'Total:', counter 42 | 43 | if __name__ == '__main__': 44 | permu([1,2,3,4]) 45 | print 46 | permu([1,1,2,3]) 47 | 48 | 49 | -------------------------------------------------------------------------------- /candy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Candy 4 | 5 | There are N children standing in a line. Each child is assigned a rating value. 6 | You are giving candies to these children subjected to the following requirements: 7 | Each child must have at least one candy. 8 | Children with a higher rating get more candies than their neighbors. 9 | 10 | What is the minimum candies you must give? 11 | ''' 12 | from __future__ import division 13 | import random 14 | 15 | def candy(scores): 16 | print scores 17 | n = len(scores) 18 | candies = [1]*n 19 | # left --> right 20 | # add one if score > child on the right 21 | for i in range(1,n): 22 | if scores[i] > scores[i-1]: 23 | candies[i] = max(candies[i], candies[i-1]+1) 24 | elif scores[i] == scores[i-1]: 25 | candies[i] = max(candies[i], candies[i-1]) 26 | print candies 27 | # right --> left 28 | # add one if score > child on the left 29 | for i in reversed(range(n-1)): 30 | if scores[i] > scores[i+1]: 31 | candies[i] = max(candies[i], candies[i+1]+1) 32 | elif scores[i] == scores[i+1]: 33 | candies[i] = max(candies[i], candies[i+1]) 34 | print candies 35 | return candies 36 | 37 | if __name__ == '__main__': 38 | candy([1,2,3,7,2,0,0,3,2,10]) 39 | 40 | 41 | -------------------------------------------------------------------------------- /count_and_say.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Count and say 4 | The count-and-say sequence is the sequence of integers beginning as follows: 5 | 1, 11, 21, 1211, 111221, ... 6 | 7 | 1 is read off as "one 1" or 11. 8 | 11 is read off as "two 1s" or 21. 9 | 21 is read off as "one 2, then one 1" or 1211. 10 | 11 | Given an integer n, generate the nth sequence. 12 | Note: The sequence of integers will be represented as a string. 13 | ''' 14 | from __future__ import division 15 | import random 16 | 17 | def count_and_say(n): 18 | if n == 0: return [] 19 | prev_s = '1' 20 | seqs = [prev_s] 21 | for i in range(1,n): 22 | cur_s = '' 23 | prev_char = prev_s[0] 24 | prev_char_count = 1 25 | for char in prev_s[1:]: 26 | # update counter 27 | if char != prev_char: 28 | cur_s += str(prev_char_count) + prev_char 29 | prev_char = char 30 | prev_char_count = 0 31 | prev_char_count += 1 32 | # leftover 33 | cur_s += str(prev_char_count) + prev_char 34 | seqs.append(cur_s) 35 | prev_s = cur_s 36 | 37 | # pretty print 38 | for i in range(1,n+1): print str(i)+'-th:', seqs[i-1] 39 | return seqs 40 | 41 | 42 | if __name__ == '__main__': 43 | print count_and_say(10) 44 | 45 | 46 | -------------------------------------------------------------------------------- /str_reorder_dist_apart.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Given a string of lowercase characters, reorder them such that the same characters are at least distance d from each other. 4 | Input: { a, b, b }, distance = 2 5 | Output: { b, a, b } 6 | ''' 7 | from __future__ import division 8 | import sys, random 9 | from collections import defaultdict 10 | 11 | 12 | # Greedy strategy: the character that has the most duplicates has the highest priority of being chosen to put in the new list. If that character cannot be chosen (due to the distance constraint), we go for the character that has the next highest priority. We also use some tables to improve the efficiency. (i.e., keeping track of # of duplicates of each character.) 13 | def reorder(L, d): 14 | n = len(L) 15 | freq = defaultdict(int) 16 | newL = [None]*n 17 | for ch in L: freq[ch] += 1 18 | while freq: 19 | ch = max(freq, key=lambda x:freq[x]) 20 | first = 0 # first available pos 21 | while newL[first] is not None: first += 1 22 | for i in range(freq[ch]): 23 | if first >= n: print 'Cannot!'; sys.exit(1) 24 | newL[first] = ch 25 | first += d 26 | del freq[ch] 27 | print L, newL 28 | return newL 29 | 30 | 31 | if __name__ == '__main__': 32 | reorder(['a','a','b','b','c','b','b','b'], 2) 33 | 34 | 35 | -------------------------------------------------------------------------------- /swap_nodes_pairs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Swap Nodes in Pairs 4 | Given a linked list, swap every two adjacent nodes and return its head. 5 | For example, Given 1->2->3->4, you should return the list as 2->1->4->3. 6 | Your algorithm should use only constant space. 7 | You may not modify the values in the list, only nodes itself can be changed. 8 | ''' 9 | from __future__ import division 10 | import random 11 | from LinkedList import Node 12 | 13 | 14 | def swap_pairs(head): 15 | print head 16 | if not head or not head.next: 17 | return head 18 | first_prev = None 19 | first = head 20 | second = head.next 21 | while first and second: 22 | # swap 23 | first.next = second.next 24 | second.next = first 25 | if first_prev: 26 | first_prev.next = second 27 | else: 28 | # first pair, change root 29 | head = second 30 | # move to the next pair 31 | if not first or not first.next: break 32 | first_prev = first 33 | first = first.next 34 | second = first.next 35 | 36 | print head 37 | return head 38 | 39 | 40 | if __name__ == '__main__': 41 | l1 = Node(1, Node(2, Node(3))) 42 | l2 = Node(2, Node(3, Node(4, Node(5, Node(6, Node(7)))))) 43 | swap_pairs(l1) 44 | swap_pairs(l2) 45 | 46 | 47 | -------------------------------------------------------------------------------- /search_range.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Search for a Range 4 | Given a sorted array of integers, find the starting and ending position of a given target value. 5 | Your algorithm's runtime complexity must be in the order of O(log n). 6 | If the target is not found in the array, return [-1, -1]. 7 | For example, 8 | Given [5, 7, 7, 8, 8, 10] and target value 8, 9 | return [3, 4]. 10 | ''' 11 | from __future__ import division 12 | import random 13 | 14 | 15 | # O(log n) in time. 16 | # Search in L[i:j] 17 | def binary_range_search(L, val, i, j): 18 | if L[i] == L[j-1] == val: return range(i,j) 19 | if i == j-1 and L[i] != val: return [] 20 | if i > j-1: return [] 21 | 22 | # L[i:mid], L[mid:j] 23 | mid = (i+j)//2 24 | lower = []; upper = [] 25 | if val <= L[mid]: 26 | lower = binary_range_search(L, val, i, mid) 27 | if val >= L[mid]: 28 | upper = binary_range_search(L, val, mid, j) 29 | return lower + upper 30 | 31 | 32 | def search_range(L, val): 33 | return binary_range_search(L, val, 0, len(L)) 34 | 35 | 36 | if __name__ == '__main__': 37 | print search_range([1,2,3,3,3,3,3,3,3,4,5,6,6,6,6,6,7], 3) 38 | print search_range([1,2,3,3,4,5,5,6,7,8,9], 3) 39 | print search_range([1,2,3], 3) 40 | print search_range([3], 3) 41 | print search_range([3,3,4,5], 3) 42 | 43 | 44 | -------------------------------------------------------------------------------- /first_missing_pos.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: First missing positive 4 | Given an unsorted integer array, find the first missing positive integer. 5 | For example, 6 | Given [1,2,0] return 3, 7 | and [3,4,-1,1] return 2. 8 | 9 | Your algorithm should run in O(n) time and uses constant space. 10 | ''' 11 | from __future__ import division 12 | import random 13 | 14 | ## Use bitmap 15 | def first_miss_pos(L): 16 | bitmap = 0 17 | for x in L: 18 | if x <= 0: continue 19 | bitmap |= (1 << (x-1)) 20 | print L, bin(bitmap) 21 | pos = 0 22 | while bitmap > 0: 23 | bitmap,r = divmod(bitmap, 2) 24 | pos += 1 25 | if r == 0: return pos 26 | return pos+1 27 | 28 | 29 | ## Switch x to pos x, amortized time ~O(n) 30 | def first_miss_pos2(L): 31 | n = len(L) 32 | print L, '-->', 33 | for i in range(len(L)): 34 | while L[i] > 0 and L[i] < n and L[i] != L[L[i]]: 35 | # switch tmp to postition tmp if it is valid (1 to n-1) 36 | tmp = L[i] 37 | L[i] = L[tmp] 38 | L[tmp] = tmp 39 | if L[i] >= n: L[i] = -1 40 | 41 | print L 42 | for i in range(1,n): 43 | if L[i] < 0: return i 44 | return n 45 | 46 | 47 | if __name__ == '__main__': 48 | print first_miss_pos2([1,2,0]) 49 | print first_miss_pos2([1,2,3]) 50 | print first_miss_pos2([3,4,-1,1]) 51 | 52 | 53 | -------------------------------------------------------------------------------- /simplify_path.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Simplify Path 4 | Given an absolute path for a file (Unix-style), simplify it. 5 | For example, 6 | path = "/home/", => "/home" 7 | path = "/a/./b/../../c/", => "/c" 8 | Corner Cases: 9 | Did you consider the case where path = "/../"? 10 | In this case, you should return "/". 11 | Another corner case is the path might contain multiple slashes '/' together, such as "/home//foo/". 12 | In this case, you should ignore redundant slashes and return "/home/foo". 13 | ''' 14 | from __future__ import division 15 | import random 16 | 17 | def simply_path(path): 18 | dirs = [] 19 | dir_name = '' 20 | for ch in path: 21 | if ch == '/': 22 | if dir_name: 23 | if dir_name == '..': dirs = dirs[:-1] 24 | elif dir_name != '.': dirs.append(dir_name) 25 | dir_name = '' 26 | else: 27 | dir_name += ch 28 | 29 | # leftover 30 | if dir_name: 31 | if dir_name == '..': dirs = dirs[:-1] 32 | elif dir_name != '.': dirs.append(dir_name) 33 | 34 | sim_path = '/' + '/'.join(dirs) 35 | print sim_path 36 | return sim_path 37 | 38 | 39 | 40 | if __name__ == '__main__': 41 | simply_path("/home/") 42 | simply_path("/home///foo/./") 43 | simply_path("/a/./b/../../c/d") 44 | simply_path("/../../") 45 | simply_path("/../../foo1/foo2/foo3") 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /max_subarray.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Maximum Subarray 4 | Find the contiguous subarray within an array (containing at least 5 | one number) which has the largest sum. 6 | For example, given the array [-2,1,-3,4,-1,2,1,-5,4], 7 | 8 | ''' 9 | from __future__ import division 10 | import random 11 | 12 | # form S[i] = sum(A[0],...A[i]) 13 | # maximize |S[j] - S[i]| where j > i 14 | def max_subarray(A): 15 | n = len(A) 16 | S = [A[0]]*n 17 | for i in range(1,n): S[i] = S[i-1] + A[i] 18 | print 'S:', S 19 | i = 0; j = n-1 20 | max_sum = None 21 | run = 0 22 | while j >= i: 23 | max_sum = max(max_sum, S[j] - S[i]) 24 | # move one step at one time. 25 | if run % 2 == 0: i += 1 26 | else: j -= 1 27 | run += 1 28 | return max_sum 29 | 30 | 31 | ''' More practice: If you have figured out the O(n) solution, 32 | try coding another solution using the divide and conquer approach, 33 | which is more subtle.''' 34 | # DP: S[i] = max sum of subarray ending at A[i] 35 | def max_subarray_DP(A): 36 | S = {} 37 | S[0] = A[0] 38 | for i in range(1, len(A)): 39 | S[i] = max(A[i], S[i-1]+A[i]) 40 | return max(S.values()) 41 | 42 | 43 | if __name__ == '__main__': 44 | print max_subarray([-2,1,-3,4,-1,2,1,-5,4]) 45 | print max_subarray_DP([-2,1,-3,4,-1,2,1,-5,4]) 46 | print max_subarray([0,0,0,0]) 47 | print max_subarray_DP([0,0,0,0]) 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /sorted2BST.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | from BinaryTree import Node as TreeNode 6 | from LinkedList import Node 7 | 8 | ''' 9 | Leetcode: Convert Sorted Array to Binary Search Tree 10 | ''' 11 | def convert2BST(arr): 12 | n = len(arr) 13 | if n == 0: return None 14 | if n == 1: return TreeNode(value=arr[0]) 15 | idx = n//2 16 | root = TreeNode( 17 | value = arr[idx], 18 | left = convert2BST(arr[:idx]), 19 | right = convert2BST(arr[idx+1:]) 20 | ) 21 | return root 22 | 23 | 24 | ''' 25 | Leetcode: Convert Sorted List to Binary Search Tree 26 | ''' 27 | # bottom-up 28 | def convert2BST_link(node, start, end): 29 | if start > end or node is None: 30 | return None, node 31 | mid = (start+end)//2 32 | left_tree, node = convert2BST_link(node, start, mid-1) 33 | root = TreeNode(value = node.value) 34 | node = node.next 35 | right_tree, node = convert2BST_link(node, mid+1, end) 36 | root.left = left_tree 37 | root.right = right_tree 38 | return root, node 39 | 40 | 41 | if __name__ == '__main__': 42 | a = [1,3,5,6,89,100,200,201] 43 | print convert2BST(a) 44 | 45 | l = Node(value=1, next=Node(value=3, next=Node(value=5,next=Node(value=6, next=Node(value=89,next=Node(value=100,next=Node(value=200,next=Node(value=201)))))))) 46 | print l 47 | print convert2BST_link(l,0,7)[0] 48 | 49 | 50 | -------------------------------------------------------------------------------- /sum_root_to_leaf_num.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Sum Root to Leaf Numbers 4 | Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number. 5 | An example is the root-to-leaf path 1->2->3 which represents the number 123. 6 | Find the total sum of all root-to-leaf numbers. 7 | For example, 8 | 1 9 | / \ 10 | 2 3 11 | The root-to-leaf path 1->2 represents the number 12. 12 | The root-to-leaf path 1->3 represents the number 13. 13 | Return the sum = 12 + 13 = 25. 14 | ''' 15 | from __future__ import division 16 | import random 17 | from BinaryTree import Node 18 | 19 | 20 | def sum_root_to_leaf(root, cur_path_num, sum): 21 | if not root.left and not root.right: 22 | cur_path_num = cur_path_num*10 + root.value 23 | print '+', cur_path_num 24 | sum += cur_path_num 25 | return sum 26 | 27 | cur_path_num = cur_path_num*10 + root.value 28 | if root.left: 29 | sum = sum_root_to_leaf(root.left, cur_path_num, sum) 30 | if root.right: 31 | sum = sum_root_to_leaf(root.right, cur_path_num, sum) 32 | return sum 33 | 34 | 35 | # Is it possible to do this iteratively? 36 | def sum_root_to_leaf_iter(): 37 | pass 38 | 39 | 40 | if __name__ == '__main__': 41 | root = Node(1, 42 | left=Node(2, left=Node(4), right=Node(1,right=Node(6))), 43 | right=Node(3, right=Node(5))) 44 | 45 | print sum_root_to_leaf(root, 0, 0) 46 | 47 | -------------------------------------------------------------------------------- /rotate_images.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Rotate Image 4 | You are given an n x n 2D matrix representing an image. 5 | Rotate the image by 90 degrees (clockwise). 6 | Follow up: Could you do this in-place? 7 | ''' 8 | from __future__ import division 9 | import random 10 | 11 | # rotate cell by cell 12 | # (i,j) --> (j, n-1-i) --> (n-1-i,n-1-j) --> (n-1-j,i) --> (i,j) 13 | def rotate_image(M): 14 | print '\n'.join(map(str,M)) + '\n' 15 | n = len(M) 16 | if n % 2 == 0: x = y = n//2 17 | else: x = n//2+1; y = n//2 18 | # the range part is tricky 19 | for i in range(x): 20 | for j in range(y): 21 | print (i,j),'->',(j, n-1-i),'->',(n-1-i,n-1-j),'->',(n-1-j,i) 22 | last = M[n-1-j][i] 23 | M[n-1-j][i] = M[n-1-i][n-1-j] 24 | M[n-1-i][n-1-j] = M[j][n-1-i] 25 | M[j][n-1-i] = M[i][j] 26 | M[i][j] = last 27 | print '\n'.join(map(str,M)) 28 | return M 29 | 30 | 31 | if __name__ == '__main__': 32 | M = [[2,0,2,1,3,0,7], 33 | [1,0,1,4,1,5,1], 34 | [0,5,10,1,4,8,2], 35 | [1,1,12,5,1,1,2], 36 | [4,6,0,5,1,2,1], 37 | [0,10,1,4,1,5,9], 38 | [0,5,101,11,4,8,2] 39 | ] 40 | rotate_image(M) 41 | print 42 | M = [[2,0,2], 43 | [1,0,1], 44 | [0,5,10] 45 | ] 46 | rotate_image(M) 47 | print 48 | M = [[1,2,3,4], 49 | [5,6,7,8], 50 | [9,10,11,12], 51 | [13,14,15,16] 52 | ] 53 | rotate_image(M) 54 | -------------------------------------------------------------------------------- /zigzag_conversion.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: ZigZag Conversion 4 | The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility) 5 | 6 | P A H N 7 | A P L S I I G 8 | Y I R 9 | And then read line by line: "PAHNAPLSIIGYIR" 10 | Write the code that will take a string and make this conversion given a number of rows: 11 | string convert(string text, int nRows); 12 | convert("PAYPALISHIRING", 3) should return "PAHNAPLSIIGYIR". 13 | ''' 14 | from __future__ import division 15 | import random 16 | 17 | # x = k+(k-2) 18 | # row 0: 0, x, 2x, 3x, ... 19 | # row 1: 1, x-1,x+1, 2x-1,2x+1, ... 20 | # row i: i, x-i,x+i, 2x-i,2x+i, ... 21 | # row k-1: k-1, x+k-1, 2x+k-1, ... 22 | def convert(S, k): 23 | n = len(S); print 'n =', n 24 | x = 2*k-2 25 | rets = "" 26 | for i in range(k): 27 | if i >= n: break # in case the string is too short. 28 | rets += S[i] 29 | j = x 30 | while j-i < n: 31 | if i == 0: 32 | rets += S[j+0] 33 | elif i == k-1: 34 | if j+i <= n-1: rets += S[j+i] 35 | else: 36 | rets += S[j-i] 37 | if j+i <= n-1: rets += S[j+i] 38 | j += x 39 | print rets 40 | return rets 41 | 42 | 43 | if __name__ == '__main__': 44 | convert("PAYPALISHIRING", 3) 45 | convert("ABCD", 5) 46 | convert("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 5) 47 | convert("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10) 48 | 49 | 50 | -------------------------------------------------------------------------------- /min_window_substr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Minimum Window Substring 4 | Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n). 5 | 6 | For example, 7 | S = "ADOBECODEBANC" 8 | T = "ABC" 9 | Minimum window is "BANC". 10 | 11 | Note: If there is no such window in S that covers all characters in T, return the emtpy string "". If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S. 12 | ''' 13 | 14 | from __future__ import division 15 | import random 16 | 17 | # O(|S|log|T|) 18 | def min_window_substr(S, T): 19 | if S == '' or T == '': return '' 20 | last_seen = {} 21 | start = 0; end = len(S)-1 22 | T = set(T) 23 | # find such a substring ended at i-th character. 24 | for i, ch in enumerate(S): 25 | if ch not in T: continue 26 | last_seen[ch] = i 27 | if len(last_seen) == len(T): 28 | # all chars have been seen 29 | first = min(last_seen.values()) #**We can use a priority queue, O(logn) 30 | if i-first+1 < end-start+1: 31 | start = first; end = i 32 | 33 | window = S[start:end+1] if len(last_seen) == len(T) else "" 34 | print window, len(window) 35 | return window 36 | 37 | 38 | if __name__ == '__main__': 39 | print min_window_substr("AFDOBECODEBANCD", "ABCF") 40 | print min_window_substr("AAABDFBFFHGKOAAFDOPPQDQPFVCCDEC", "ACD") 41 | print min_window_substr("AAABBBB", "AB") 42 | print min_window_substr("", "") 43 | 44 | 45 | -------------------------------------------------------------------------------- /wildcard_matching.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Wildcard Matching 4 | Implement wildcard pattern matching with support for '?' and '*'. 5 | 6 | '?' Matches any single character. 7 | '*' Matches any sequence of characters (including the empty sequence). 8 | 9 | The matching should cover the entire input string (not partial). 10 | The function prototype should be: 11 | bool isMatch(const char *s, const char *p) 12 | Some examples: 13 | isMatch("aa","a") ? false 14 | isMatch("aa","aa") ? true 15 | isMatch("aaa","aa") ? false 16 | isMatch("aa", "*") ? true 17 | isMatch("aa", "a*") ? true 18 | isMatch("ab", "?*") ? true 19 | isMatch("aab", "c*a*b") ? false 20 | ''' 21 | from __future__ import division 22 | import random 23 | 24 | def wildcard_match(s, p): 25 | if len(p) == 0: return len(s) == 0 26 | # s can be empty 27 | if p[0] == '?': 28 | return len(s) > 0 and wildcard_match(s[1:], p[1:]) 29 | elif p[0] == '*': 30 | # match nothing or 31 | # match one and continue, AB* = A* 32 | return wildcard_match(s, p[1:]) or \ 33 | (len(s) > 0 and wildcard_match(s[1:], p)) 34 | else: 35 | return len(s) > 0 and s[0] == p[0] and wildcard_match(s[1:], p[1:]) 36 | 37 | return False 38 | 39 | 40 | if __name__ == '__main__': 41 | print wildcard_match("aa","a") 42 | print wildcard_match("aa","aa") 43 | print wildcard_match("aaa","aa") 44 | print wildcard_match("aa", "*") 45 | print wildcard_match("aa", "a*") 46 | print wildcard_match("ab", "?*") 47 | print wildcard_match("aab", "c*a*b") 48 | 49 | 50 | -------------------------------------------------------------------------------- /partition_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Partition List 4 | Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x. You should preserve the original relative order of the nodes in each of the two partitions. 5 | 6 | For example, 7 | Given 1->4->3->2->5->2 and x = 3, 8 | return 1->2->2->4->3->5. 9 | ''' 10 | from __future__ import division 11 | import random 12 | from LinkedList import Node 13 | 14 | 15 | def part_list(head, val): 16 | dummy = Node(None, next=head) 17 | node = head 18 | small = dummy # the end of "small part" of the link 19 | large = dummy # the end of "large part" of the link 20 | while node: 21 | print head, 'small:', small.value, 'large:', large.value, 22 | print 'current:', node, 'next:', node.next 23 | next_node = node.next 24 | if node.value >= val: 25 | large = node 26 | else: 27 | # Change the connection 28 | if small.next != node: 29 | print 'move', node.value 30 | node.next = small.next 31 | small.next = node 32 | large.next = next_node 33 | # update the tail pointer to the small part 34 | small = node 35 | node = next_node 36 | head = dummy.next 37 | print head 38 | return head 39 | 40 | 41 | if __name__ == '__main__': 42 | L = Node(1, Node(4, Node(3, Node(2, Node(5, Node(2)))))) 43 | part_list(L, 3) 44 | L = Node(5, Node(2, Node(4, Node(4, Node(1, Node(2)))))) 45 | part_list(L, 4) 46 | 47 | -------------------------------------------------------------------------------- /comb_sum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode 4 | Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. 5 | Note: 6 | All numbers (including target) will be positive integers. 7 | Elements in a combination (a1,a2,..,ak) must be in non-descending order. (ie, a1 <= a2 <= .. <= ak). The solution set must not contain duplicate combinations. 8 | ''' 9 | from __future__ import division 10 | import random 11 | 12 | 13 | ''' 14 | The same repeated number may be chosen from C unlimited number of times. 15 | For example, given candidate set 2,3,6,7 and target 7, a solution set is: 16 | [7] 17 | [2, 2, 3] 18 | ''' 19 | def comb_sum(C, k): 20 | if k == 0: yield [] 21 | for x in C: 22 | if k >= x: 23 | for p in comb_sum(C, k-x): 24 | yield sorted([x] + p) 25 | 26 | 27 | ''' 28 | Each number in C may only be used once in the combination. 29 | For example, given candidate set 10,1,2,7,6,1,5 and target 8, 30 | A solution set is: 31 | [1, 7] 32 | [1, 2, 5] 33 | [2, 6] 34 | [1, 1, 6] 35 | ''' 36 | def comb_sum2(C, k): 37 | if k == 0: yield [] 38 | n = len(C) 39 | for i in range(n): 40 | if k >= C[i]: 41 | for p in comb_sum(C[:i]+C[i+1:], k-C[i]): 42 | yield sorted([C[i]] + p) 43 | 44 | 45 | if __name__ == '__main__': 46 | c1 = set([",".join(map(str,p)) for p in comb_sum([2,3,6,7], 7)]) 47 | c2 = set([",".join(map(str,p)) for p in comb_sum2([10,1,2,7,6,1,5], 8)]) 48 | 49 | for p in c1: print p 50 | print 51 | for p in c2: print p 52 | print 53 | 54 | 55 | -------------------------------------------------------------------------------- /divide_two_nums.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Divide Two Integers 4 | Divide two integers without using multiplication, division and mod operator. 5 | ''' 6 | from __future__ import division 7 | import random 8 | 9 | def divide_two_nums(x, y): # x/y 10 | if y == 0: return None 11 | q = 0 12 | a = long(x); b = long(y) 13 | if y < 0: b = ~b + 1 14 | while a > b: 15 | a -= b 16 | q += 1 17 | if y < 0: q = ~q + 1 18 | return q 19 | 20 | ############################################## 21 | 22 | 23 | def bit_add(x, y): 24 | carry = x & y 25 | result = x ^ y 26 | while carry != 0: 27 | shifted_carry = carry << 1 28 | # try to add shifted carry and result 29 | carry = result & shifted_carry 30 | result = result ^ shifted_carry 31 | return result 32 | 33 | def bit_add2(x, y): 34 | while True: 35 | carry = x & y 36 | result = x ^ y 37 | x = carry << 1 38 | y = result 39 | if carry == 0: break 40 | return y 41 | 42 | def bit_sub(x, y): 43 | print x, bin(x) 44 | print ~y+1, bin(~y+1) 45 | return bit_add2(x, ~y+1) 46 | 47 | def bit_multi(x, y): 48 | result = 0 49 | for i in range(y): 50 | result = bit_add(result, x) 51 | return result 52 | 53 | ''' Divide two integers using only bitwise operations ''' 54 | def bit_divide(x, y): 55 | pass 56 | 57 | if __name__ == '__main__': 58 | print 234, 11 59 | print divide_two_nums(234,11) 60 | print divide_two_nums(234,-11) 61 | print bit_add(234,11) 62 | #print bit_sub(234,11) 63 | print bit_multi(234,11) 64 | 65 | 66 | -------------------------------------------------------------------------------- /add_binary.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Add binary 4 | 5 | Given two binary strings, return their sum (also a binary string). 6 | 7 | For example, 8 | a = "11" 9 | b = "1" 10 | Return "100". 11 | ''' 12 | from __future__ import division 13 | import random 14 | 15 | def valid_binary_str(s): 16 | for bit in list(s): 17 | if bit != '0' and bit != '1': return False 18 | return True 19 | 20 | # Special cases: negative numbers? not a valid binary string? 21 | def add_binary(a, b): 22 | if (not valid_binary_str(a)) or (not valid_binary_str(b)): return None 23 | 24 | print a,'+',b,'=', 25 | # make a and b of equal lengths 26 | l = max(len(a), len(b)) 27 | while len(a) < l: a = '0'+a 28 | while len(b) < l: b = '0'+b 29 | 30 | i = l-1 31 | results = "" 32 | prev_carry = 0 33 | while i >= 0: 34 | x, y = int(a[i]), int(b[i]) 35 | # add current bits 36 | z = x ^ y 37 | cur_carry = x & y 38 | # add previous carry 39 | if prev_carry == 1: 40 | if z == 1: z = 0; cur_carry = 1 41 | else: z = 1 42 | 43 | cur_carry = (z & prev_carry) | cur_carry 44 | z = z ^ prev_carry 45 | 46 | results = str(z) + results 47 | prev_carry = cur_carry 48 | i -= 1 49 | # last carry 50 | if prev_carry: results = '1'+results 51 | print results 52 | return results 53 | 54 | 55 | 56 | 57 | if __name__ == '__main__': 58 | add_binary('11','1') 59 | add_binary('101011','1111') 60 | add_binary('101','1111') 61 | add_binary('0','0') 62 | add_binary('11','1222') 63 | 64 | 65 | -------------------------------------------------------------------------------- /grey_code.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Gray Code 4 | The gray code is a binary numeral system where two successive values differ in only one bit. Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0. 5 | 6 | For example, given n = 2, return [0,1,3,2]. Its gray code sequence is: 7 | 00 - 0 8 | 01 - 1 9 | 11 - 3 10 | 10 - 2 11 | Note: 12 | For a given n, a gray code sequence is not uniquely defined. For example, [0,2,3,1] is also a valid gray code sequence according to the above definition. 13 | 14 | http://www.matrix67.com/blog/archives/266 15 | n-th gray code: n xor (n >> 1) 16 | ''' 17 | from __future__ import division 18 | import random 19 | 20 | def print_int(codes): 21 | for c in codes: 22 | print c, '-', int(c,2) 23 | 24 | 25 | def gray_code(n): 26 | if n == 1: return ['0','1'] 27 | prev_codes = grey_code(n-1) 28 | codes = [] 29 | for c in prev_codes: 30 | codes.append('0'+c) 31 | for c in reversed(prev_codes): 32 | codes.append('1'+c) 33 | return codes 34 | 35 | 36 | def gray_code_iter(n): 37 | codes = ['0','1'] 38 | for i in range(1,n): 39 | new_codes = ['0'+c for c in codes] + \ 40 | ['1'+c for c in reversed(codes)] 41 | codes = new_codes 42 | return codes 43 | 44 | 45 | def gray_code_bit(n): 46 | ret = [] 47 | count = 1 << n; 48 | for i in range(count): 49 | ret.append( bin(i ^ (i >> 1)) ) 50 | return ret 51 | 52 | 53 | if __name__ == '__main__': 54 | print_int(gray_code_bit(3)) 55 | print_int(gray_code_iter(3)) 56 | 57 | 58 | -------------------------------------------------------------------------------- /min_path_sum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Minimum Path Sum 4 | Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path. 5 | Note: You can only move either down or right at any point in time. 6 | ''' 7 | from __future__ import division 8 | import random 9 | 10 | # DP: S(i,j) = min path sum from (0,0)-->(i,j) 11 | # S(i,j) = min{S(i-1,j), S(i,j-1)} + M(i,j) 12 | # ~ O(mn) 13 | def min_path_sum(M): 14 | rows, cols = len(M), len(M[0]) 15 | S = {}; prev = {} 16 | S[0,0] = M[0][0] 17 | prev[0,0] = None 18 | for i in range(1,rows): 19 | S[i,0] = S[i-1,0] + M[i][0] 20 | prev[i,0] = (i-1,0) 21 | for j in range(1,cols): 22 | S[0,j] = S[0,j-1] + M[0][j] 23 | prev[0,j] = (0,j-1) 24 | 25 | for i in range(1, rows): 26 | for j in range(1, cols): 27 | if S[i-1,j] < S[i,j-1]: 28 | S[i,j] = S[i-1,j] + M[i][j] 29 | prev[i,j] = (i-1, j) 30 | else: 31 | S[i,j] = S[i,j-1] + M[i][j] 32 | prev[i,j] = (i,j-1) 33 | paths = [] 34 | step = (rows-1, cols-1) 35 | while step and step in prev: 36 | paths.insert(0, step) 37 | step = prev[step] 38 | print 'path:', '-->'.join(map(str,paths)) 39 | print S[rows-1, cols-1] 40 | return paths 41 | 42 | 43 | if __name__ == '__main__': 44 | M = [[2,0,2,1,3,0,7], 45 | [1,0,1,4,1,5,1], 46 | [0,5,10,1,4,8,2], 47 | [1,1,12,5,1,1,2], 48 | [4,6,0,5,1,2,1] 49 | ] 50 | print '\n'.join(map(str,M)) 51 | min_path_sum(M) 52 | 53 | 54 | -------------------------------------------------------------------------------- /triangle.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Triangle 4 | Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below. 5 | For example, given the following triangle 6 | [ [2], 7 | [3,4], 8 | [6,5,7], 9 | [4,1,8,3]] 10 | The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11). 11 | 12 | Note: Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle. 13 | ''' 14 | from __future__ import division 15 | import random 16 | 17 | # S[i][j] = min{S[i-1][j-1], S[i-1][j]} + T[i][j] 18 | # We only need to keep the record of the last row 19 | # S[j] = min{S[j-1], S[j]} + T[i][j]} 20 | # top-down 21 | def triangle(T): 22 | if not T: return 0 23 | S = [ T[0][0] ] 24 | for i in range(1,len(T)): 25 | print S 26 | newS = [] 27 | for j in range(len(T[i])): 28 | if j == 0: newS.append( S[0] + T[i][j] ) 29 | elif j == len(S): newS.append( S[len(S)-1] + T[i][j] ) 30 | else: newS.append( min(S[j-1], S[j]) + T[i][j] ) 31 | S = newS 32 | print newS 33 | return min(newS) 34 | 35 | 36 | # More pretty code: bottom-up 37 | def triangle2(T): 38 | if not T: return 0 39 | n = len(T) 40 | S = [0]*(n+1) 41 | while n >= 0: 42 | # There are n+1 elements on n-th row 43 | for i in range(0, n): 44 | S[i] = T[n-1][i] + min(S[i],S[i+1]) 45 | n -= 1 46 | return S[0] 47 | 48 | 49 | if __name__ == '__main__': 50 | T = [ [2], 51 | [3,4], 52 | [6,5,7], 53 | [4,1,8,3]] 54 | triangle2(T) 55 | 56 | 57 | -------------------------------------------------------------------------------- /valid_BST.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Valid Binary Search Tree 4 | Given a binary tree, determine if it is a valid binary search tree (BST). 5 | 6 | Assume a BST is defined as follows: 7 | The left subtree of a node contains only nodes with keys less than the node's key. 8 | The right subtree of a node contains only nodes with keys greater than the node's key. 9 | Both the left and right subtrees must also be binary search trees. 10 | ''' 11 | from __future__ import division 12 | import random 13 | from BinaryTree import Node, BST, root 14 | 15 | 16 | def valid_BST(root): 17 | if not root.left and not root.right: 18 | return True 19 | 20 | left_valid = right_valid = False 21 | 22 | if root.left: 23 | print root.left.value, '<=', root.value 24 | if root.left.value <= root.value: 25 | left_valid = valid_BST(root.left) 26 | 27 | if root.right: 28 | print root.value, '<=', root.right.value 29 | if root.right.value >= root.value: 30 | right_valid = valid_BST(root.right) 31 | 32 | return left_valid and right_valid 33 | 34 | 35 | if __name__ == '__main__': 36 | BST2 = Node(value=5, 37 | left=Node(value=2, 38 | left=Node(value=1), 39 | right=Node(value=3) 40 | ), 41 | right=Node(value=9, 42 | left=Node(value=7), 43 | right=Node(value=16, 44 | right=Node(value=15) 45 | ) 46 | ) 47 | ) 48 | 49 | print valid_BST(BST) 50 | print valid_BST(BST2) 51 | print valid_BST(root) 52 | 53 | 54 | -------------------------------------------------------------------------------- /word_search.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Word Search 4 | Given a 2D board and a word, find if the word exists in the grid. 5 | The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once. 6 | For example, 7 | Given board = 8 | [ 9 | ["ABCE"], 10 | ["SFCS"], 11 | ["ADEE"] 12 | ] 13 | word = "ABCCED", -> returns true, 14 | word = "SEE", -> returns true, 15 | word = "ABCB", -> returns false. 16 | ''' 17 | from __future__ import division 18 | import random 19 | 20 | # start from i,j 21 | def word_search_from_cell(M, word, i, j): 22 | if len(word) == 0: 23 | return True 24 | 25 | if i is not None and j is not None: 26 | cands = ((i+1,j), (i-1,j), (i,j+1), (i,j-1)) 27 | else: 28 | cands = ((x,y) for x in range(len(M)) for y in range(len(M[0]))) 29 | 30 | # (x,y) are adjacent cell to (i,j) 31 | for x,y in cands: 32 | if 0 <=x< len(M) and 0<=y max_len: 31 | max_len = cur_len 32 | start = cur_start 33 | end = i 34 | print s, ':', max_len, s[start:end+1] 35 | return max_len 36 | 37 | 38 | if __name__ == '__main__': 39 | longest_valid_parentheses(")()()(()()())())))") 40 | longest_valid_parentheses("(()") 41 | longest_valid_parentheses("") 42 | longest_valid_parentheses(")()(()(()(") 43 | longest_valid_parentheses("(((()(((") 44 | longest_valid_parentheses("))))))(((((") 45 | 46 | 47 | -------------------------------------------------------------------------------- /maximum_product_subarray.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | class Solution: 5 | # @param A, a list of integers 6 | # @return an integer 7 | def maxProduct(self, A): 8 | # subproblem is maxProduct(A[n-1]) 9 | # looks like optimal substructrure, dp should be applicable 10 | # 11 | # let's use: 12 | # m: positive product for A[x:i], initial with 0 13 | # n: negative product for A[x:i], initial with 0 14 | # 15 | # for example [2,3,-2,4] 16 | # i 2 3 -2 4 17 | # m 2 6 0 4 18 | # n 0 0 -12 -48 19 | # best 2 6 6 6 20 | if not A: 21 | raise ValueError 22 | if len(A) == 1: 23 | return A[0] 24 | 25 | m, n, best = 0, 0, float('-inf') 26 | for i in A: 27 | if i >= 0: 28 | m, n = max(m * i, i), n * i 29 | else: 30 | m, n = n * i, min(m * i, i) 31 | best = max(m, best) 32 | return best 33 | 34 | 35 | 36 | class Test(unittest.TestCase): 37 | 38 | def test(self): 39 | s = Solution() 40 | self.assertEqual(s.maxProduct([-2,0,-1]), 0) 41 | self.assertEqual(s.maxProduct([-4,-3,-2]), 12) 42 | self.assertEqual(s.maxProduct([2,3,-2,4]), 6) 43 | self.assertEqual(s.maxProduct([-2]), -2) 44 | self.assertEqual(s.maxProduct([0.1, 0.1, 2]), 2) 45 | self.assertEqual(s.maxProduct([-2, 2, -2]), 8) 46 | self.assertEqual(s.maxProduct([0, -2, 4]), 4) 47 | self.assertEqual(s.maxProduct([0, -2, -2, 4]), 16) 48 | self.assertEqual(s.maxProduct([1, -2, 2, 2, 4]), 16) 49 | 50 | 51 | if __name__ == '__main__': 52 | unittest.main() 53 | -------------------------------------------------------------------------------- /add_two_nums.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Add Two Numbers 4 | 5 | You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. 6 | 7 | Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) 8 | Output: 7 -> 0 -> 8 9 | ''' 10 | from __future__ import division 11 | import random 12 | 13 | class DigitNode(object): 14 | def __init__(self, digit, next=None): 15 | self.digit = digit 16 | self.next = next 17 | def __str__(self): 18 | if next: 19 | return 'DigitNode(%d, %s)' % (self.digit, str(self.next)) 20 | else: 21 | return 'DigitNode(%d)' % (self.digit) 22 | 23 | def add_two_numbers(a, b): 24 | prev_carry = 0 25 | orig_node = None 26 | prev_node = None 27 | while a and b: 28 | digit = (a.digit + b.digit + prev_carry) % 10 29 | cur_carry = (a.digit + b.digit + prev_carry) // 10 30 | node = DigitNode(digit) 31 | if prev_node: prev_node.next = node 32 | else: orig_node = node 33 | a = a.next 34 | b = b.next 35 | prev_carry = cur_carry 36 | prev_node = node 37 | # leftover 38 | x = a if a else b 39 | while x: 40 | digit = (x.digit + prev_carry) % 10 41 | cur_carry = (x.digit + prev_carry) // 10 42 | node = DigitNode(digit) 43 | if prev_node: prev_node.next = node 44 | x = x.next 45 | prev_carry = cur_carry 46 | prev_node = node 47 | return orig_node 48 | 49 | 50 | if __name__ == '__main__': 51 | a = DigitNode(2, DigitNode(4, DigitNode(3, DigitNode(5)))) 52 | b = DigitNode(5, DigitNode(6, DigitNode(4, DigitNode(1, DigitNode(2))))) 53 | print add_two_numbers(a,b) 54 | 55 | -------------------------------------------------------------------------------- /set_matrix_zeros.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Set Matrix Zeroes 4 | Given a m x n matrix, if an element is 0, set its entire row and column to 0. 5 | Do it in place. 6 | Did you use extra space? 7 | A straight forward solution using O(mn) space is probably a bad idea. 8 | A simple improvement uses O(m + n) space, but still not the best solution. 9 | Could you devise a constant space solution? 10 | ''' 11 | from __future__ import division 12 | import random 13 | 14 | 15 | # O(1) in space 16 | # use the first row and column as a buffer 17 | def set_matrix_zeros(M): 18 | m = len(M); n = len(M[0]) 19 | first_row_zero = first_col_zero = False 20 | # find zeros in first row/column 21 | for i in range(m): 22 | if M[i][0] == 0: 23 | first_col_zero = True 24 | break 25 | for j in range(n): 26 | if M[0][j] == 0: 27 | first_row_zero = True 28 | break 29 | # record zeros in other places 30 | for i in range(1,m): 31 | for j in range(1,n): 32 | if M[i][j] == 0: 33 | M[0][j] = 0 34 | M[i][0] = 0 35 | # set zeros 36 | for i in range(m): 37 | if M[i][0] == 0: 38 | for j in range(1,n): 39 | M[i][j] = 0 40 | for j in range(n): 41 | if M[0][j] == 0: 42 | for i in range(1,m): 43 | M[i][j] = 0 44 | 45 | print '\n'.join(map(str,M)) 46 | 47 | 48 | if __name__ == '__main__': 49 | 50 | M = [[2,5,2,1,3,6,7], 51 | [1,2,1,4,1,0,1], 52 | [7,5,10,1,4,8,2], 53 | [1,1,12,5,1,1,2], 54 | [4,0,2,5,1,2,1], 55 | [3,10,1,4,1,5,9], 56 | [3,5,101,11,4,8,2] 57 | ] 58 | print '\n'.join(map(str,M)), '\n' 59 | set_matrix_zeros(M) 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /longest_consec_seq.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Longest Consecutive Sequence 4 | Given an unsorted array of integers, find the length of the longest consecutive elements sequence. 5 | 6 | For example, Given [100, 4, 200, 1, 3, 2], The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4. 7 | 8 | Your algorithm should run in O(n) complexity. 9 | ''' 10 | from __future__ import division 11 | import random 12 | 13 | # Using bitmap 14 | def consecutive_seq(L): 15 | bitmap = 0 16 | for x in L: bitmap |= 1 << x 17 | max_len = cur_len = 0 18 | print bitmap, bin(bitmap) 19 | while bitmap > 0: 20 | bitmap, r = divmod(bitmap, 2) 21 | if r == 1: 22 | cur_len += 1 23 | else: 24 | max_len = max(max_len, cur_len) 25 | cur_len = 0 26 | return max_len 27 | 28 | 29 | # Using extra space to merge seq 30 | # Think as cluster merge, a single number is a length=1 cluster. 31 | # Map lowest and highest to length. To merge two neighbor clusters, only need to update it's new lowest and highest, with new length. 32 | # For every a[i], checking its neighbor a[i]-1 and a[i]+1 is enough. 33 | def merge(seq, x, y): 34 | a, b = min(seq[x][0], seq[y][0]), max(seq[x][1], seq[y][1]) 35 | seq[x] = [a,b]; seq[y] = [a,b] 36 | seq[a] = [a,b]; seq[b] = [a,b] 37 | return seq 38 | 39 | def consecutive_seq2(L): 40 | seq = {} # mapping: x -> sequence [a,b] that contains x 41 | for x in L: 42 | if x in seq: continue 43 | seq[x] = [x,x] 44 | if x-1 in seq: seq = merge(seq, x, x-1) 45 | if x+1 in seq: seq = merge(seq, x, x+1) 46 | print seq 47 | return max([b-a+1 for a,b in seq.values()]) 48 | 49 | 50 | if __name__ == '__main__': 51 | print consecutive_seq2([4,10,8,200,1,3,30,5,12,3,1,2,2,7,70,6,9,9,11,18,16,19]) 52 | 53 | 54 | -------------------------------------------------------------------------------- /jump_game.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | 6 | ''' 7 | Leetcode: Jump Game 8 | Given an array of non-negative integers, you are initially positioned at the first index of the array. Each element in the array represents your *maximum* jump length at that position. 9 | Determine if you are able to reach the last index. 10 | For example: 11 | A = [2,3,1,1,4], return true. 12 | A = [3,2,1,0,4], return false. 13 | ''' 14 | # DP 15 | # R(i) = whether we can arrive at the last index from i-th element 16 | # R(i) = R(i+1) or R(i+2) or ... or R(i+A[i]) 17 | # R(len(A)-1) = True 18 | def jump_game(A): 19 | n = len(A) 20 | R = {n-1:True} 21 | for pos in reversed(xrange(n-1)): 22 | R[pos] = False 23 | for next_pos in range(pos+1, min(pos+A[pos]+1, n)): 24 | R[pos] |= R[next_pos] 25 | print R 26 | return R[0] 27 | 28 | 29 | ''' 30 | Leetcode: Jump Game II 31 | Your goal is to reach the last index in the minimum number of jumps. 32 | For example: 33 | Given array A = [2,3,1,1,4] 34 | The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.) 35 | ''' 36 | # DP 37 | # R(i) = minimum #steps we can arrive at the last index from i-th element (-1/None means we cannot) 38 | # R(i) = min{R(i+1) or R(i+2) or ... or R(i+A[i])} + 1 39 | # R(len(A)-1) = 0 40 | def jump_game2(A): 41 | n = len(A) 42 | R = {n-1:0} 43 | for pos in reversed(xrange(n-1)): 44 | R[pos] = None 45 | for next_pos in range(pos+1, min(pos+A[pos]+1, n)): 46 | # Note any number > None 47 | if (R[next_pos] >= 0) and \ 48 | ((R[pos] is None) or (R[next_pos]+1 < R[pos])): 49 | R[pos] = R[next_pos] + 1 50 | print R 51 | return R[0] 52 | 53 | 54 | if __name__ == '__main__': 55 | print jump_game2([2,3,1,1,4]) 56 | print jump_game2([3,2,1,0,4]) 57 | 58 | 59 | -------------------------------------------------------------------------------- /copy_list_random_pointer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Copy List with Random Pointer 4 | A linked list is given such that each node contains an additional random pointer 5 | which could point to any node in the list or null. Return a deep copy of the list. 6 | ''' 7 | 8 | from __future__ import division 9 | import random 10 | import LinkedList 11 | 12 | 13 | class Node(LinkedList.Node): 14 | def __init__(self, value, next=None, prev=None, randp=None): 15 | super(Node, self).__init__(value, next, prev) 16 | self.randp = randp 17 | def __str__(self): 18 | if self.randp is None: s = '[%d]' % self.value 19 | else: s = '[%d,%d]' % (self.value, self.randp.value) 20 | if self.next: 21 | s += '->(%s)' % str(self.next) 22 | return s 23 | 24 | # Brute-force 25 | # create the list first and then set up the pointer 26 | def copylist(head): 27 | new_head = Node(head.value) 28 | # Copy the list 29 | prev_n = new_head 30 | node = head.next 31 | while node: 32 | n = Node(node.value) 33 | prev_n.next = n 34 | prev_n = n 35 | node = node.next 36 | 37 | # Assign pointer 38 | node = head 39 | new_node = new_head 40 | while node: 41 | if node.randp: 42 | # locate the pointer 43 | h = head 44 | newh = new_head 45 | while h != node.randp: 46 | h = h.next 47 | newh = newh.next 48 | new_node.randp = newh 49 | node = node.next 50 | new_node = new_node.next 51 | print 'Orig:', head 52 | print 'Copy:', new_head 53 | 54 | 55 | if __name__ == '__main__': 56 | n6 = Node(6) 57 | n5 = Node(5, n6) 58 | n4 = Node(4, n5) 59 | n3 = Node(3, n4) 60 | n2 = Node(2, n3) 61 | n1 = Node(1, n2) 62 | n1.randp = n4 63 | n2.randp = n4 64 | n4.randp = n6 65 | n5.randp = n3 66 | 67 | copylist(n1) 68 | 69 | 70 | -------------------------------------------------------------------------------- /interleaving_str.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Interleaving String 4 | Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. 5 | For example, Given: 6 | s1 = "aa b c c", 7 | s2 = "dbb ca", 8 | When s3 = "aa d b b c bca c", return true. 9 | When s3 = "aa dbb b accc", return false. 10 | ''' 11 | from __future__ import division 12 | import random 13 | 14 | def interleaving(s1,s2,s3): 15 | if (s3 == '' and s1 == '' and s2 == '') or (s1 == '' and s2 == s3) or (s2 == '' and s1 == s3): 16 | return True 17 | elif s1 == '' or s2 == '' or s3 == '': 18 | return False 19 | else: 20 | ch = s3[0] 21 | if ch == s1[0] and ch != s2[0]: 22 | return interleaving(s1[1:], s2, s3[1:]) 23 | elif ch != s1[0] and ch == s2[0]: 24 | return interleaving(s1, s2[1:], s3[1:]) 25 | elif ch == s1[0] and ch == s2[0]: 26 | return interleaving(s1, s2[1:], s3[1:]) or \ 27 | interleaving(s1[1:], s2, s3[1:]) 28 | else: 29 | return False 30 | 31 | 32 | # DP? 33 | # I(i,j) = whether s3[:i+j] is an interleaving string of s1[:i] and s2[:j] 34 | # I(i+1,j) = I(i,j) if s1[i] == s3[i+j] 35 | # I(i,j+1) = I(i,j) if s2[i] == s3[i+j] 36 | def interleaving_DP(s1, s2, s3): 37 | n, m = len(s1), len(s2) 38 | if len(s3) != n+m: return False 39 | I = {} 40 | I[0,0] = True 41 | for ij in range(1, n+m+1): 42 | for i in range(min(n+1, ij+1)): 43 | j = ij - i 44 | if j > m: continue 45 | I[i,j] = (i >= 1 and I[i-1,j] and (s1[i-1] == s3[ij-1])) or \ 46 | (j >= 1 and I[i,j-1] and (s2[j-1] == s3[ij-1])) 47 | return I[n,m] 48 | 49 | 50 | if __name__ == '__main__': 51 | s1 = "aabcc" 52 | s2 = "dbbca" 53 | print interleaving(s1, s2, "aadbbcbcac"), interleaving_DP(s1, s2, "aadbbcbcac") 54 | print interleaving(s1, s2, "aadbbbaccc"), interleaving_DP(s1, s2, "aadbbbaccc") 55 | 56 | 57 | -------------------------------------------------------------------------------- /same_tree.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Same Tree 4 | Given two binary trees, write a function to check if they are equal or not. 5 | Two binary trees are considered equal if they are structurally identical and the nodes have the same value. 6 | ''' 7 | from __future__ import division 8 | import random 9 | from BinaryTree import Node 10 | 11 | 12 | def is_same_tree(root1, root2): 13 | if (not root1.left) and not (root1.right) and (not root2.left) and not (root2.right) and root1.value == root2.value: 14 | return True 15 | 16 | if (root1.value != root2.value) or (root1.left and not root2.left) or (not root1.left and root2.left) or (root1.right and not root2.right) or (not root1.right and root2.right): return False 17 | 18 | left = is_same_tree(root1.left, root2.left) \ 19 | if root1.left and root2.left \ 20 | else True 21 | right = is_same_tree(root1.right, root2.right) \ 22 | if root1.right and root2.right \ 23 | else True 24 | return left and right 25 | 26 | 27 | if __name__ == '__main__': 28 | root1 = Node(value=5, 29 | left=Node(value=4, 30 | left=Node(value=11, 31 | left=Node(value=6), 32 | right=Node(value=2)) 33 | ), 34 | right=Node(value=8, 35 | left=Node(value=13), 36 | right=Node(value=4, 37 | left=Node(value=5), 38 | right=Node(value=1)) 39 | ) 40 | ) 41 | 42 | root2 = Node(value=0, 43 | left=Node(value=4, 44 | left=Node(value=11) 45 | ), 46 | right=Node(value=8, 47 | left=Node(value=13), 48 | right=Node(value=4) 49 | ) 50 | ) 51 | 52 | print is_same_tree(root1, root1) 53 | print is_same_tree(root1, root2) -------------------------------------------------------------------------------- /binary_tree_traversal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | from BinaryTree import Node, SampleTreeRoot 6 | 7 | ''' 8 | Leetcode: Binary Tree Inorder Traversal 9 | Given a binary tree, return the inorder traversal of its nodes' values. 10 | For example: Given binary tree {1,#,2,3}, 11 | 1 12 | \ 13 | 2 14 | / 15 | 3 16 | return [1,3,2]. 17 | Note: Recursive solution is trivial, could you do it iteratively? 18 | ''' 19 | def binary_tree_inorder_traversal(): 20 | pass 21 | 22 | 23 | 24 | ''' 25 | Leetcode: Binary Tree Level Order Traversal 26 | Given a binary tree, return the level order traversal of its nodes' values. 27 | (ie, from left to right, level by level). 28 | For example: Given binary tree {3,9,20,#,#,15,7}, 29 | 3 30 | / \ 31 | 9 20 32 | / \ 33 | 15 7 34 | return its level order traversal as: 35 | [ 36 | [3], 37 | [9,20], 38 | [15,7] 39 | ]''' 40 | def func(): 41 | pass 42 | 43 | 44 | ''' 45 | Leetcode: Binary Tree Level Order Traversal II 46 | Given a binary tree, return the bottom-up level order traversal of its nodes' values. 47 | (ie, from left to right, level by level from leaf to root). 48 | For example: Given binary tree {3,9,20,#,#,15,7}, 49 | 3 50 | / \ 51 | 9 20 52 | / \ 53 | 15 7 54 | return its bottom-up level order traversal as: 55 | [ 56 | [15,7] 57 | [9,20], 58 | [3], 59 | ]''' 60 | def func(): 61 | pass 62 | 63 | 64 | ''' 65 | LeetCode: Binary Tree Zigzag Level Order Traversal 66 | Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between). 67 | For example: Given binary tree {3,9,20,#,#,15,7}, 68 | 3 69 | / \ 70 | 9 20 71 | / \ 72 | 15 7 73 | return its zigzag level order traversal as: 74 | [ 75 | [3], 76 | [20,9], 77 | [15,7] 78 | ]''' 79 | def func(): 80 | pass 81 | 82 | 83 | if __name__ == '__main__': 84 | func() 85 | 86 | 87 | -------------------------------------------------------------------------------- /valid_number.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Valid Number 4 | 5 | Validate if a given string is numeric. 6 | Some examples: 7 | "0" => true 8 | " 0.1 " => true 9 | "abc" => false 10 | "1 a" => false 11 | "2e10" => true 12 | 13 | Note: It is intended for the problem statement to be ambiguous. You should gather all requirements up front before implementing one. 14 | ''' 15 | 16 | from __future__ import division 17 | import sys, random 18 | 19 | # integer: negative sign/integer 20 | # float 21 | # scientific notation: 'e'/'E' 22 | # hex number?? 23 | # other base k number? 24 | # complex number?? 25 | # fraction?? 26 | # 27 | # [space*][+?/-?][digits*][.?][digits+][e/E][+?/-?][digits*][.?][digits+][space*] 28 | def valid_number(s): 29 | print s, 30 | s = s.strip() 31 | subs = s.lower().split('e') 32 | if len(subs) > 2: return False # too many e's 33 | if len(subs) == 2 and len(subs[1]) == 0: return False # no number after e 34 | 35 | for sub in subs: 36 | # each sub is a valid number (without 'e') 37 | # [+?/-?][digits*][.?][digits+] 38 | has_dot = False 39 | has_digits = 0 40 | if sub[0] in ['+','-']: sub = sub[1:] 41 | sub_secs = sub.split('.') 42 | if len(sub_secs) > 2: # two many dots 43 | return False 44 | # Each sub_secs should be empty or only digits 45 | for sec in sub_secs: 46 | for ch in sec: 47 | if not ch.isdigit(): 48 | return False 49 | return True 50 | 51 | 52 | ### Use finite turing machine 53 | 54 | 55 | if __name__ == '__main__': 56 | print valid_number("0") 57 | print valid_number(" 0.1") 58 | print valid_number("abc") 59 | print valid_number("1 a") 60 | print valid_number("2.e5") 61 | print valid_number("2e10") 62 | print valid_number(" 3.5e4.5 ") 63 | print valid_number("56.8.9") 64 | print valid_number("-12.3E.11") 65 | print valid_number("-12.3E") 66 | print valid_number("+2.") 67 | 68 | 69 | -------------------------------------------------------------------------------- /distinct_subseq.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Distinct Subsequences 4 | 5 | Given a string S and a string T, count the number of distinct subsequences of T in S. A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not). 6 | Here is an example: 7 | S = "rabbbit", T = "rabbit" 8 | Return 3. 9 | ra[b]bbit 10 | rab[b]bit 11 | rabb[b]it 12 | ''' 13 | from __future__ import division 14 | import random 15 | 16 | # DP: 17 | # f(i,j) = #distinct subsequences of S[:i] and T[:j] 18 | # f(i,j) = f(i-1,j) if not use S[i-1] 19 | # f(i,j) = f(i-1,j-1) if S[i-1] == T[j-1] and use S[i-1] 20 | # Thus, f(i,j) = f(i-1,j) + (S[i-1] == T[j-1])*f(i-1,j-1) 21 | def distinct_subseq(S, T): 22 | n=len(S); m=len(T) 23 | W = {} 24 | # Initialization 25 | for i in range(n+1): W[0] = 1 # if T is empty 26 | for j in range(1, m+1): W[j] = 0 # if S is empty but T is not. 27 | for i in range(1, n+1): 28 | for j in range(1, m+1): 29 | # W[j] --> short for W[i,j] 30 | W[j] += W[j-1]*(S[i-1]==T[j-1]) 31 | return W[m] 32 | 33 | 34 | # DP: Let f(i,j) to be the number of distinct subsequences of T(j:) in S(i:). 35 | # Consider the ith character in S: 36 | # If we can use it to match T[j], namely S[i] == T[j], then f(i,j) = f(i+1,j+1). 37 | # If we do not want use it in our matching, then f(i,j) = f(i+1,j). 38 | # Thus, f(i,j) = f(i+1,j) + (S[i] == T[j])*f(i+1,j+1) 39 | # It is very much the same as how we solve C(n, m) or the knapsack problem. 40 | def distinct_subseq2(S, T): 41 | m = len(S); n = len(T) 42 | f = dict((j,0) for j in range(n+1)) 43 | f[n] = 1 44 | for i in reversed(xrange(m)): 45 | for j in xrange(n): 46 | f[j] += (S[i] == T[j])*f[j+1] 47 | return f[0] 48 | 49 | 50 | if __name__ == '__main__': 51 | print distinct_subseq("rabbbit", "rabbit") 52 | 53 | 54 | -------------------------------------------------------------------------------- /binary_tree_path_sum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Binary Tree Maximum Path Sum 4 | Given a binary tree, find the maximum path sum. 5 | The path may start and end at any node in the tree. 6 | For example: Given the below binary tree, 7 | 1 8 | / \ 9 | 2 3 10 | Return 6. 11 | 2-1-3 12 | ''' 13 | 14 | from __future__ import division 15 | import random 16 | from BinaryTree import Node, SampleTreeRoot 17 | 18 | # L(node) = max sum path in node's left sub-tree 19 | # R(node) = max sum path in node's right sub-tree 20 | # L(node) = node.val + max{L(node.left), R(node.left)} 21 | # R(node) = node.val + max{L(node.right), R(node.right)} 22 | # max{L(node)+R(node) for any node in the tree} 23 | def subtree_maxsum_path(node, is_left=True, Lpath={}, Rpath={}): 24 | if is_left: 25 | # left sub-tree 26 | if not node.left: 27 | Lpath[node.id] = 0 28 | return 0 29 | else: 30 | Lpath[node.id] = node.value + max( 31 | subtree_maxsum_path(node.left, True, Lpath, Rpath), 32 | subtree_maxsum_path(node.left, False, Lpath, Rpath) 33 | ) 34 | return Lpath[node.id] 35 | else: 36 | # right sub-tree 37 | if not node.right: 38 | Rpath[node.id] = 0 39 | return 0 40 | else: 41 | Rpath[node.id] = node.value + max( 42 | subtree_maxsum_path(node.right, True, Lpath, Rpath), 43 | subtree_maxsum_path(node.right, False, Lpath, Rpath) 44 | ) 45 | return Rpath[node.id] 46 | 47 | 48 | def maxsum_path(root): 49 | Lpath = {} 50 | Rpath = {} 51 | subtree_maxsum_path(root, True, Lpath, Rpath) 52 | subtree_maxsum_path(root, False, Lpath, Rpath) 53 | print 'Left-path:', Lpath 54 | print 'Right-path:', Rpath 55 | path2sum = dict((i, Lpath[i]+Rpath[i]) for i in Lpath.keys()) 56 | i = max(path2sum, key=path2sum.get) 57 | print 'The path going through node', i, 'with max sum', path2sum[i] 58 | return path2sum[i] 59 | 60 | 61 | if __name__ == '__main__': 62 | print maxsum_path(SampleTreeRoot) 63 | 64 | 65 | -------------------------------------------------------------------------------- /uniq_BST.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | from __future__ import division 5 | import random 6 | from BinaryTree import Node 7 | 8 | ''' 9 | Leetcode: Unique Binary Search Trees 10 | Given n, how many structurally unique BST's (binary search trees) that store values 1...n? 11 | For example, Given n = 3, there are a total of 5 unique BST's. 12 | 1 3 3 2 1 13 | \ / / / \ \ 14 | 3 2 1 1 3 2 15 | / / \ \ 16 | 2 1 2 3 17 | ''' 18 | # P(n) = #structurally unique BST 19 | # Pick a root r from 1,2,...,n 20 | # 1,..,r-1 ---> P(r-1) 21 | # r+1,...,n ---> P(n-r) 22 | # P(n) = sum(P(r-1)*P(n-r) for r=1,2,...,n) 23 | # So we have P(n) = (2n)!/n!*(n+1)! <--- catalan number 24 | def uniq_BST(n): 25 | P = {0:1, 1:1} 26 | for i in range(2,n+1): 27 | P[i] = 0 28 | for root in range(1,i+1): 29 | P[i] += P[root-1] * P[i-root] 30 | return P[n] 31 | 32 | 33 | ''' 34 | Leetcode: Unique Binary Search Trees II 35 | Given n, generate all structurally unique BST's (binary search trees) that store values 1...n. 36 | For example, given n = 3, your program should return all 5 unique BST's shown below. 37 | 1 3 3 2 1 38 | \ / / / \ \ 39 | 3 2 1 1 3 2 40 | / / \ \ 41 | 2 1 2 3 42 | ''' 43 | def gen_uniq_BST(i,j): 44 | if i > j: yield None 45 | elif i == j: yield Node(i) 46 | else: 47 | for root in range(i,j+1): 48 | node = Node(root) 49 | for left_node in gen_uniq_BST(i,root-1): 50 | for right_node in gen_uniq_BST(root+1,j): 51 | node.left = left_node 52 | node.right = right_node 53 | yield node 54 | 55 | def uniq_BST_II(n): 56 | print uniq_BST(n) 57 | total = 0 58 | for tree in gen_uniq_BST(1,n): 59 | print tree 60 | total += 1 61 | print 'total:', total 62 | 63 | 64 | if __name__ == '__main__': 65 | uniq_BST_II(4) 66 | 67 | 68 | -------------------------------------------------------------------------------- /path_sum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | from BinaryTree import Node, root, root_with_id 6 | 7 | ''' 8 | Leetcode: Path Sum 9 | Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum. 10 | For example: Given the below binary tree and sum = 22, 11 | 5 12 | / \ 13 | 4 8 14 | / / \ 15 | 11 13 4 16 | / \ \ 17 | 7 2 1 18 | return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22. 19 | ''' 20 | def path_sum(root, val): 21 | if not root: return False 22 | if not root.left and not root.right: return val == root.value 23 | return path_sum(root.left, val-root.value) or path_sum(root.right, val-root.value) 24 | 25 | 26 | ''' 27 | Leetcode: Path Sum II 28 | Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum. 29 | For example: Given the below binary tree and sum = 22, 30 | 5 31 | / \ 32 | 4 8 33 | / / \ 34 | 11 13 4 35 | / \ / \ 36 | 6 2 5 1 37 | return 38 | [ 39 | [5,4,11,2], 40 | [5,8,4,5] 41 | ] 42 | ''' 43 | def path_finder(root, val, path, paths): 44 | if not root: 45 | return False 46 | 47 | if not root.left and not root.right: 48 | if root.value == val: 49 | path.append(root.value) 50 | paths.append(path) 51 | return True 52 | else: 53 | return False 54 | 55 | left = path_finder(root.left, val-root.value, path+[root.value], paths) 56 | right = path_finder(root.right, val-root.value, path+[root.value], paths) # make sure it can be executed! 57 | return left or right 58 | 59 | 60 | def path_sum2(root, val): 61 | paths = [] 62 | path_finder(root, val, [], paths) 63 | print 'sum:', val 64 | print 'paths:', paths 65 | 66 | 67 | if __name__ == '__main__': 68 | path_sum2(root_with_id, 4) 69 | path_sum2(root_with_id, -4) 70 | 71 | path_sum2(root, 22) 72 | path_sum2(root, 26) 73 | 74 | 75 | -------------------------------------------------------------------------------- /uniq_paths.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | 6 | 7 | ''' 8 | Leetcode: Unique Paths 9 | A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below). How many possible unique paths are there? 10 | Note: m and n will be at most 100. 11 | ''' 12 | # i = 0,1,...,m-1; j = 0,1,...,n-1 13 | # P(i,j) = P(i-1,j) + P(i,j-1) 14 | # P(i,j) = C(i+j, i) 15 | def uniq_paths(m,n): 16 | ret = 1 17 | # What is C(m+n-2, n-1) 18 | # m/1 * (m+1)/2 * ... * (m+n-2)/(n-1) 19 | for i in range(1,n): 20 | ret *= (m+i-1)/i 21 | return ret 22 | 23 | 24 | ''' 25 | Leetcode: Unique Paths II 26 | Now consider if some obstacles are added to the grids. How many unique paths would there be? An obstacle and empty space is marked as 1 and 0 respectively in the grid. 27 | For example, There is one obstacle in the middle of a 3x3 grid as illustrated below. 28 | [ 29 | [0,0,0], 30 | [0,1,0], 31 | [0,0,0] 32 | ] 33 | The total number of unique paths is 2. 34 | Note: m and n will be at most 100. 35 | ''' 36 | # P(i,j) = 0 if M[i][j] == 1 37 | # P(i-1,j) + P(i,j-1) otherwise 38 | def uniq_paths_II(M): 39 | m = len(M); n = len(M[0]) 40 | P = {} 41 | for i in range(m): P[i,0] = 1-M[i][0] 42 | for j in range(n): P[0,j] = 1-M[0][j] 43 | for i in range(1,m): 44 | for j in range(1,n): 45 | P[i,j] = (P[i-1,j]+P[i,j-1])*(1-M[i][j]) 46 | 47 | for i in range(m): 48 | for j in range(n): 49 | print P[i,j], 50 | print 51 | 52 | return P[m-1,n-1] 53 | 54 | 55 | 56 | if __name__ == '__main__': 57 | print uniq_paths(5,7) 58 | print uniq_paths(3,3) 59 | 60 | M = [[0,0,0,1,0,0], 61 | [0,1,0,0,0,1], 62 | [0,0,0,0,1,0], 63 | [1,0,0,0,0,0]] 64 | print '\n'.join(map(str,M)),'\n' 65 | uniq_paths_II(M) 66 | 67 | M = [[0,0,0], 68 | [0,1,0], 69 | [0,0,0]] 70 | print '\n'.join(map(str,M)),'\n' 71 | uniq_paths_II(M) 72 | 73 | -------------------------------------------------------------------------------- /int_to_roman.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | 6 | 7 | ''' 8 | Leetcode: Integer to Roman 9 | Given an integer, convert it to a roman numeral. 10 | Input is guaranteed to be within the range from 1 to 3999. 11 | 12 | 1) I can be placed before V and X to make 4 units (IV) and 9 units (IX) 13 | 2) X can be placed before L and C to make 40 (XL) and 90 (XC) 14 | 3) C can be placed before D and M to make 400 (CD) and 900 (CM) 15 | ''' 16 | def int_to_roman(num): 17 | print num, 18 | if num <= 0: return None 19 | val2sym = {1:'I', 5:'V', 10:'X', 50:'L', 100:'C', 500:'D', 1000:'M'} 20 | vals = sorted(val2sym.keys(), reverse=True) 21 | roman = '' 22 | for val in vals: 23 | n, num = divmod(num, val) 24 | last_digit = roman[-1] if len(roman) > 0 else '' 25 | if n == 4 and val == 1: 26 | roman = roman[:-1]+'IX' if last_digit=='V' else roman+'IV' 27 | elif n == 4 and val == 10: 28 | roman = roman[:-1]+'XC' if last_digit=='L' else roman+'XL' 29 | elif n == 4 and val == 100: 30 | roman = roman[:-1]+'CM' if last_digit=='D' else roman+'CD' 31 | else: 32 | roman += val2sym[val]*n 33 | print roman 34 | return roman 35 | 36 | 37 | ''' 38 | Leetcode: Roman to Int 39 | Given a roman numeral, convert it to an integer. 40 | Input is guaranteed to be within the range from 1 to 3999. 41 | 1) I can be placed before V and X to make 4 units (IV) and 9 units (IX) 42 | 2) X can be placed before L and C to make 40 (XL) and 90 (XC) 43 | 3) C can be placed before D and M to make 400 (CD) and 900 (CM) 44 | ''' 45 | def roman_to_int(roman): 46 | val2sym = {1:'I', 5:'V', 10:'X', 50:'L', 100:'C', 500:'D', 1000:'M'} 47 | sym2val = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000} 48 | # Replace 4, 9, 40, 90, 400, 900 49 | for i in [1,10,100]: 50 | roman = roman.replace(val2sym[i]+val2sym[5*i], val2sym[i]*4) 51 | roman = roman.replace(val2sym[i]+val2sym[10*i], val2sym[5*i]+val2sym[i]*4) 52 | 53 | ret = sum([sym2val[ch] for ch in roman]) 54 | print roman, ret 55 | return ret 56 | 57 | 58 | if __name__ == '__main__': 59 | int_to_roman(290) 60 | roman_to_int('CCIX') 61 | 62 | 63 | -------------------------------------------------------------------------------- /valid_sudoku.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Valid Sudoku 4 | Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. 5 | The Sudoku board could be partially filled, where empty cells are filled with the character '.'. 6 | A partially filled sudoku which is valid. 7 | ''' 8 | from __future__ import division 9 | import random 10 | 11 | INVALID = '.' 12 | 13 | # fill in (x,y) with val@ 14 | def check_conflict(M, x, y, val): 15 | # column 16 | for i in range(9): 17 | if M[i][y] != INVALID: 18 | if M[i][y] == val: 19 | return True 20 | # row 21 | for j in range(9): 22 | if M[x][j] != INVALID: 23 | if M[x][j] == val: 24 | return True 25 | # cubes 26 | for i in range((x//3)*3, (x//3)*3+3): 27 | for j in range((y//3)*3, (x//3)*3+3): 28 | if M[i][j] != INVALID: 29 | if M[i][j] == val: 30 | return True 31 | return False 32 | 33 | 34 | # whether the sudoku is valid 35 | def is_valid_sudoku(M): 36 | N = 9 37 | assert len(M) == N and len(M[0]) == N 38 | # row; no repetition between 0~9. 39 | for i in range(N): 40 | if not valid_array(M[i]): 41 | return False 42 | # col 43 | for j in range(N): 44 | if not valid_array([M[i][j] for i in range(N)]): 45 | return False 46 | 47 | # 3x3 cells 48 | for x in range(0,9,3): 49 | for y in range(0,9,3): 50 | A = [M[i][j] for i in range(x,x+3) for j in range(y,y+3)] 51 | if not valid_array(A): 52 | return False 53 | return True 54 | 55 | 56 | def valid_array(A): 57 | if len(set(A)) == len(A) and min(A) >= 1 and max(A) <= 9: return True 58 | return False 59 | 60 | 61 | if __name__ == '__main__': 62 | M = [[5,3,0,0,7,0,0,0,0], 63 | [6,0,0,1,9,5,0,0,0], 64 | [0,9,8,0,0,0,0,6,0], 65 | [8,0,0,0,6,0,0,0,3], 66 | [4,0,0,8,0,3,0,0,1], 67 | [7,0,0,0,2,0,0,0,6], 68 | [0,6,0,0,0,0,2,8,0], 69 | [0,0,0,4,1,9,0,0,5], 70 | [0,0,0,0,8,0,0,7,9]] 71 | print check_conflict(M, 0, 2, 4) 72 | print check_conflict(M, 5, 3, 9) 73 | print check_conflict(M, 8, 6, 5) 74 | 75 | 76 | -------------------------------------------------------------------------------- /sort_colors.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Sort Colors 4 | 5 | Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue. Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively. 6 | Note: You are not suppose to use the library's sort function for this problem. 7 | ''' 8 | from __future__ import division 9 | import random 10 | 11 | 12 | '''A rather straight forward solution is a two-pass algorithm using counting sort. First, iterate the array counting number of 0's, 1's, and 2's, then overwrite array with total number of 0's, then 1's and followed by 2's.''' 13 | def sort_colors(L): 14 | from collections import Counter 15 | counter = Counter(L) 16 | for i,x in enumerate(counter.elements()): L[i] = x 17 | return L 18 | 19 | ''' 20 | Follow up: Could you come up with an one-pass algorithm using only constant space? 21 | ''' 22 | 23 | def sort_colors2(L): 24 | n = len(L) 25 | zero = 0; two = n-1 26 | # Write 1 at the beginning; 2 at the end. 27 | cur = 0 28 | while cur <= two: 29 | print cur, L, zero, two 30 | if L[cur] == 0: 31 | if cur > zero: 32 | L[zero], L[cur] = L[cur], L[zero] 33 | zero += 1 34 | else: # TRICKY PART. 35 | # cur == zero and L[cur] == L[zero] == 0 36 | cur += 1 37 | zero += 1 38 | 39 | elif L[cur] == 2: 40 | if cur < two: 41 | L[two], L[cur] = L[cur], L[two] 42 | two -= 1 43 | else: 44 | break 45 | else: 46 | cur += 1 47 | print L, '\n' 48 | return L 49 | 50 | 51 | def sort_colors3(A): 52 | n = len(A) 53 | k = 0; zero = 0; two = n-1 54 | while k <= two: 55 | if A[k] == 0 and zero < k: 56 | A[k], A[zero] = A[zero], A[k] 57 | while A[zero] == 0: zero += 1 58 | 59 | elif A[k] == 2 and k < two: 60 | A[k], A[two] = A[two], A[k] 61 | while A[two] == 2: two -= 1 62 | else: 63 | k += 1 64 | print k, zero, two, A 65 | print A 66 | 67 | 68 | if __name__ == '__main__': 69 | sort_colors2([2,0,1,0,2,1,2,2,1,1]) 70 | sort_colors2([2,1,2,1,2,0]) 71 | sort_colors2([0,0,1,2,2,2,0,0,0]) 72 | -------------------------------------------------------------------------------- /spiral_matrix.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | http://leetcode.com/2010/05/printing-matrix-in-spiral-order.html 4 | ''' 5 | 6 | from __future__ import division 7 | import random 8 | 9 | 10 | ''' 11 | Leetcode: Spiral Matrix 12 | Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order. 13 | For example, Given the following matrix: 14 | [ 15 | [ 1, 2, 3 ], 16 | [ 4, 5, 6 ], 17 | [ 7, 8, 9 ] 18 | ] 19 | You should return [1,2,3,6,9,8,7,4,5]. 20 | ''' 21 | # Each circle starts at (i,i) 22 | # (i,i) -----> (i,m-1-i) 23 | # ^ | 24 | # | v 25 | # (n-1-i,i) <--- (n-1-i,m-1-i) 26 | def spiral_matrix_traversal(M): 27 | rets = [] 28 | m = len(M); n = len(M[0]) 29 | for i in range(min(m,n)//2): 30 | # starting point (i,i) 31 | x,y = i,i 32 | # Those -1 or +1 are tricky; avoid duplication 33 | for y in range(i,n-i): rets.append(M[x][y]) 34 | for x in range(i+1,m-i): rets.append(M[x][y]) 35 | for y in reversed(range(i,n-i-1)): rets.append(M[x][y]) 36 | for x in reversed(range(i+1,m-i-1)): rets.append(M[x][y]) 37 | print rets 38 | return rets 39 | 40 | 41 | ''' 42 | Leetcode: Spiral Matrix II 43 | Given an integer n, generate a square matrix filled with elements from 1 to n2 in spiral order. 44 | For example, Given n = 3, 45 | You should return the following matrix: 46 | [ 47 | [ 1, 2, 3 ], 48 | [ 8, 9, 4 ], 49 | [ 7, 6, 5 ] 50 | ] 51 | ''' 52 | def spiral_matrix_print(n): 53 | # initialize 54 | M = [[0 for j in range(n)] for i in range(n)] 55 | cur = 1 56 | for i in range(n//2+1): 57 | # starting point (i,i) 58 | x,y = i,i 59 | # Those -1 or +1 are tricky; avoid duplication 60 | for y in range(i,n-i): M[x][y] = cur; cur += 1 61 | for x in range(i+1,n-i): M[x][y] = cur; cur += 1 62 | for y in reversed(range(i,n-i-1)): M[x][y] = cur; cur += 1 63 | for x in reversed(range(i+1,n-i-1)): M[x][y] = cur; cur += 1 64 | 65 | print '\n'.join(map(str,M)), '\n' 66 | return M 67 | 68 | 69 | if __name__ == '__main__': 70 | M = [[1,2,3,4,5], 71 | [6,7,8,9,10], 72 | [11,12,13,14,15], 73 | [16,17,18,19,20]] 74 | #print '\n'.join(map(str,M)) 75 | #spiral_matrix_traversal(M) 76 | spiral_matrix_print(3) 77 | spiral_matrix_print(5) 78 | spiral_matrix_print(6) 79 | 80 | 81 | -------------------------------------------------------------------------------- /3sum_closest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: 3Sum Closest 4 | 5 | Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution. 6 | 7 | For example, given array S = {-1 2 1 -4}, and target = 1. 8 | The sum that is closest to the target is 2. (-1 + 2 + 1 = 2). 9 | 10 | ''' 11 | from __future__ import division 12 | import random 13 | 14 | ### DP? Given a list L 15 | # S(i, k, target) = True if we can find k elements among L[:i] to sum up to target 16 | # S(i, k, target) = S(i-1, k-1, target-L[i-1]) or S(i-1, k, target) 17 | def sum_closest(L, num_k, target): 18 | import math 19 | n = len(L) 20 | S = {} 21 | prev = {} 22 | max_t = sum([x for x in L if x > 0]) 23 | min_t = sum([x for x in L if x <= 0]) 24 | print 'target range: [%d, %d]' %(min_t, max_t) 25 | 26 | # Initialization: 27 | # S(0,any,any) = False 28 | # S(any,0,any) = False 29 | # S(any,0,0) = True 30 | for i in range(n+1): 31 | for t in range(min_t, max_t+1): 32 | S[(i,0,t)] = False 33 | for k in range(num_k+1): 34 | for t in range(min_t, max_t+1): 35 | S[(0,k,t)] = False 36 | for i in range(n+1): 37 | S[(i,0,0)] = True 38 | 39 | for i in range(1,n+1): 40 | for k in range(1,num_k+1): 41 | for t in range(min_t, max_t+1): 42 | with_elem = S[(i-1,k-1,t-L[i-1])] if min_t <= t-L[i-1] <= max_t else False 43 | without_elem = S[(i-1,k,t)] 44 | 45 | S[(i,k,t)] = with_elem or without_elem 46 | if with_elem: prev[(i,k,t)] = (i-1,k-1,t-L[i-1]) 47 | elif without_elem: prev[(i,k,t)] = (i-1,k,t) 48 | 49 | # min{|t-target| for S[(n,num_k,t)] == True} 50 | cands = [t for t in range(min_t, max_t+1) if S[(n,num_k,t)]] 51 | output_t = min(cands, key=lambda x:math.fabs(x-target)) 52 | 53 | # print out 54 | output = [] 55 | i,k,t = n,num_k,output_t 56 | while (i,k,t) in prev: 57 | next_i,next_k,next_t = prev[(i,k,t)] 58 | if next_k == k-1: output.append(L[next_i]) 59 | i,k,t = next_i,next_k,next_t 60 | print 'output:', output, 'sum(output):', sum(output) 61 | return output 62 | 63 | 64 | if __name__ == '__main__': 65 | sum_closest([-1, 2, 1, -3, 6], 2, 2) 66 | 67 | 68 | -------------------------------------------------------------------------------- /regex_match.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Regular Expression Matching 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 | The function prototype should be: bool isMatch(const char *s, const char *p) 9 | Some examples: 10 | isMatch("aa","a") -> false 11 | isMatch("aa","aa") -> true 12 | isMatch("aaa","aa") -> false 13 | isMatch("aa", "a*") -> true 14 | isMatch("aa", ".*") -> true 15 | isMatch("ab", ".*") -> true 16 | isMatch("aab", "c*a*b") -> true 17 | 18 | http://leetcode.com/2011/09/regular-expression-matching.html 19 | DFA: http://swtch.com/~rsc/regexp/regexp1.html 20 | ''' 21 | from __future__ import division 22 | import random 23 | 24 | 25 | def split_pattern(p): 26 | plist = [] 27 | while len(p) > 0: 28 | if len(p) == 1: 29 | plist.append( p[0] ) 30 | p = p[1:] 31 | else: 32 | if p[1] == '*': 33 | plist.append( p[:2] ) 34 | p = p[2:] 35 | else: 36 | plist.append( p[0] ) 37 | p = p[1:] 38 | print 'formatted pattern:', plist 39 | return plist 40 | 41 | 42 | def is_match(s, plist): 43 | #print s, plist, 44 | if len(plist) == 0: return len(s) == 0 45 | '''if len(s) == 0: 46 | for p in plist: 47 | if not p.endswith('*'): return False 48 | return True''' 49 | 50 | p = plist[0] 51 | # p has no '*' 52 | if not p.endswith('*'): 53 | #print 'matching', (s[0] if len(s) > 0 else ''), 'and', p 54 | if p.startswith('.'): 55 | return len(s) > 0 and is_match(s[1:], plist[1:]) 56 | else: 57 | return len(s) > 0 and s[0] == p and is_match(s[1:], plist[1:]) 58 | 59 | # p has '*' 60 | else: 61 | #print 'matching', p 62 | if p.startswith('.'): 63 | return is_match(s, plist[1:]) or (len(s) > 0 and is_match(s[1:], plist)) 64 | else: 65 | return is_match(s, plist[1:]) or (len(s) > 0 and s[0] == p[0] and is_match(s[1:], plist)) 66 | 67 | 68 | if __name__ == '__main__': 69 | print is_match('aaaaaabc', split_pattern('aa*bc*.*')) 70 | print is_match('aaaaaabc', split_pattern('aa*b..')) 71 | print is_match('aaaaaa', split_pattern('aaa')) 72 | print is_match('', split_pattern('aaa')) 73 | print is_match('xyz', split_pattern('...')) 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /insert_interval.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Insert Interval. 4 | Given a set of [[[non-overlapping]]] intervals, insert a new interval into the intervals (merge if necessary). You may assume that the intervals were initially sorted according to their start times. 5 | Example 1: Given intervals [1,3],[6,9], insert and merge [2,5] in as [1,5],[6,9]. 6 | Example 2: Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as [1,2],[3,10],[12,16]. This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10]. 7 | ''' 8 | from __future__ import division 9 | import random 10 | 11 | # interval tree? segment tree? 12 | 13 | # [1,3],[6,9] --> index 14 | # [-inf. 1)->0; [1,3]->1; (3,6)->2; [6,9]->3; (9,inf.)->4 15 | def insert_interval(intvs, new_intv): 16 | left, right = new_intv 17 | ret_intvs = [] 18 | new_intv_inserted = False 19 | for a,b in intvs: 20 | if left > b: # not overlap at all 21 | ret_intvs.append([a,b]) 22 | elif right < a: 23 | if not new_intv_inserted: # not overlap at all 24 | ret_intvs.append([left,right]) 25 | new_intv_inserted = True 26 | ret_intvs.append([a,b]) 27 | else: 28 | # starting/ending point in the interval 29 | if a <= left <= b: left = a 30 | if a <= right <= b: right = b 31 | # leftover 32 | if not new_intv_inserted: 33 | ret_intvs.append([left,right]) 34 | return ret_intvs 35 | 36 | 37 | ## in-place 38 | def insert_interval2(intvs, new_intv): 39 | intvs = sorted(intvs, key=lambda x:x[0]) 40 | i = 0 41 | while i < len(intvs): 42 | cur = intvs[i] 43 | if new_intv[1] < cur[0] or new_intv[0] > cur[1]: 44 | i += 1 45 | else: 46 | left = min(cur[0], new_intv[0]) 47 | right = max(cur[1], new_intv[1]) 48 | new_intv = [left, right] 49 | del intvs[i] 50 | intvs.append(new_intv) 51 | return intvs 52 | 53 | 54 | if __name__ == '__main__': 55 | intvs = [[1,2],[3,5],[6,7],[8,10],[12,16]]; new_intv = [4,9] 56 | print insert_interval2(intvs, new_intv) 57 | 58 | intvs = [[1,10],[12,16]]; new_intv = [2,8] 59 | print insert_interval2(intvs, new_intv) 60 | 61 | intvs = [[1,10],[12,16]]; new_intv = [-5,0] 62 | print insert_interval2(intvs, new_intv) 63 | 64 | intvs = [[1,10],[12,16]]; new_intv = [20,20] 65 | print insert_interval2(intvs, new_intv) 66 | 67 | 68 | -------------------------------------------------------------------------------- /search_rotated_sorted_arr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Search in Rotated Sorted Array 4 | Leetcode: Search in Rotated Sorted Array II 5 | http://leetcode.com/2010/04/searching-element-in-rotated-array.html 6 | ''' 7 | from __future__ import division 8 | import random 9 | 10 | 11 | ''' 12 | Suppose a sorted array is rotated at some pivot unknown to you beforehand. 13 | (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). 14 | You are given a target value to search. 15 | If found in the array return its index, otherwise return -1. 16 | You may assume no duplicate exists in the array. 17 | ''' 18 | # modified binary search, O(logn) 19 | # Search in L[i:j] 20 | def search_rotated_arr(L, val): 21 | l = 0; r = len(L)-1 22 | while l <= r: 23 | mid = (l + r + 1)//2 24 | if L[mid] == val: return mid 25 | if L[l] <= L[mid]: 26 | # the lower half is sorted 27 | if L[l] <= val <= L[mid]: r = mid-1 28 | else: l = mid+1 29 | else: 30 | # the upper half is sorted 31 | if L[mid] <= val <= L[r]: l = mid+1 32 | else: r = mid-1 33 | return -1 34 | 35 | 36 | def find_rotated_pivot(L): 37 | l = 0; r = len(L)-1 38 | while L[l] > L[r]: 39 | mid = (l + r + 1)//2 40 | if L[mid] > L[r]: l = mid+1 41 | else: r = mid 42 | return l 43 | 44 | ''' 45 | What if duplicates are allowed? 46 | Would this affect the run-time complexity? How and why? 47 | Write a function to determine if a given target is in the array. 48 | ''' 49 | def search_rotated_arr2(L, val, i, j): 50 | #print L[i:j] 51 | if i == j-1: 52 | return L[i] == val 53 | elif i >= j-1: 54 | return False 55 | else: 56 | mid = (i+j)//2 57 | if L[mid] == val: return True 58 | lower = upper = False 59 | if (L[i] >= L[mid]) or (val < L[mid]): 60 | lower = search_rotated_arr2(L, val, i, mid) 61 | if (L[mid] >= L[j-1]) or (L[mid] < val): 62 | upper = search_rotated_arr2(L, val, mid, j) 63 | return lower or upper 64 | 65 | 66 | if __name__ == '__main__': 67 | print search_rotated_arr([4,5,6,7,0,1,2], 6, 0, 7) 68 | print search_rotated_arr([4,5,6,7,0,1,2], 0, 0, 7) 69 | print search_rotated_arr([4,5,6,7,0,1,2], 3, 0, 7) 70 | print 71 | print search_rotated_arr2([4,5,7,0,1,2,4,4], 7, 0, 8) 72 | print search_rotated_arr2([4,5,6,7,0,0,1,2], 0, 0, 8) 73 | print search_rotated_arr2([4,4,4,4,5,2], 3, 0, 6) 74 | 75 | 76 | -------------------------------------------------------------------------------- /next_permutation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Next Permutation 4 | 5 | Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers. If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order). 6 | 7 | Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column. 8 | 1,2,3 -> 1,3,2 9 | 3,2,1 -> 1,2,3 10 | 1,1,5 -> 1,5,1 11 | 12 | No extra memory!!!! 13 | ''' 14 | from __future__ import division 15 | import random 16 | 17 | ### scan from the last digit to find the first element < the left element. 18 | # Example 1: 19 | # 1,5,3,4,2 (find 3,4) 20 | # 2,5,4,3,2 (switch 3,4) 21 | # Example 2: 22 | # 1,5,4,3,2,1,0 (find 1; the first element (1) < the right element (5).) 23 | # 1,5,4,3,2,1,0 (find 2, the first element > 1 from the end) 24 | # 2,5,4,3,1,1,0 (switch 1,2) 25 | # 2,0,1,1,3,4,5 (reverse 5,4,3,1,1,0) 26 | def next_permu(L): 27 | n = len(L) 28 | if n == 0: return [] 29 | if n == 1: return L 30 | 31 | i = n - 2 32 | while i >= 0: 33 | if L[i] < L[i+1]: break 34 | i -=1 35 | # All elements are larger than the right element 36 | if i < 0: return L[::-1] 37 | 38 | j = n - 1 39 | while L[j] <= L[i]: 40 | j -= 1 41 | # Switch i-th and j-th elements 42 | L[i], L[j] = L[j], L[i] 43 | # Reverse L[i+1:] 44 | L = L[:i+1] + L[i+1:][::-1] 45 | return L 46 | 47 | 48 | ''' 49 | Iteratively permute a string and print out lexicographically 50 | O(1) in space. 51 | ''' 52 | def iter_permutation(L): 53 | L = sorted(L) 54 | n = len(L) 55 | print L 56 | while True: 57 | i = n - 2 58 | # Find i-th element that < right element 59 | while i >= 0: 60 | if L[i] < L[i+1]: break 61 | i -=1 62 | # All elements are larger than the right element 63 | if i < 0: break 64 | 65 | j = n - 1 66 | while L[j] <= L[i]: 67 | j -= 1 68 | # Switch i-th and j-th elements 69 | L[i], L[j] = L[j], L[i] 70 | # Reverse L[i+1:] 71 | L = L[:i+1] + L[i+1:][::-1] 72 | print L 73 | 74 | 75 | 76 | if __name__ == '__main__': 77 | next_permu([1,2,3,4]) 78 | next_permu([9,9,9,8]) 79 | next_permu([0,2,1,1]) 80 | next_permu([2,3,1]) 81 | next_permu([3,2,1]) 82 | next_permu([1,5,3,4,2]) 83 | next_permu([1,5,4,3,2]) 84 | next_permu([1,5,4,3,2,1]) 85 | 86 | 87 | -------------------------------------------------------------------------------- /arithmetic_str.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import division 3 | import random 4 | 5 | def add_str(a,b): 6 | carry = 0 7 | sum = "" 8 | i = len(a)-1; j = len(b)-1 9 | while i >= 0 and j >= 0: 10 | x, y = int(a[i]), int(b[j]) 11 | carry, z = divmod(x+y+carry, 10) 12 | sum = str(z) + sum 13 | i -= 1; j -= 1 14 | 15 | while i >= 0: 16 | carry, z = divmod(carry+int(a[i]), 10) 17 | sum = str(z) + sum 18 | i -= 1 19 | while j >= 0: 20 | carry, z = divmod(carry+int(b[j]), 10) 21 | sum = str(z) + sum 22 | j -= 1 23 | # leftover 24 | if carry != 0: sum = str(carry) + sum 25 | #print a+' + '+b+' = '+sum 26 | return sum 27 | 28 | 29 | def sub_str(a,b): 30 | pass 31 | 32 | 33 | def div_str(a,b): 34 | pass 35 | 36 | 37 | ''' 38 | Leetcode: Multiple Strings 39 | Given two numbers represented as strings, return multiplication of the numbers as a string. 40 | Note: The numbers can be arbitrarily large and are non-negative. 41 | ''' 42 | def multi_str(a,b): 43 | tmp_sums = [] 44 | if len(b) > len(a): a,b = b,a 45 | i = 0 46 | for y in reversed(b): 47 | y = int(y) 48 | carry = 0 49 | tmp_sum = "" 50 | for x in reversed(a): 51 | carry, z = divmod(int(x)*y+carry, 10) 52 | tmp_sum = str(z) + tmp_sum 53 | if carry > 0: tmp_sum = str(carry) + tmp_sum 54 | tmp_sums.append(tmp_sum + '0'*i) 55 | i += 1 56 | 57 | final = '0' 58 | for s in tmp_sums: final = add_str(final, s) 59 | print a+' * '+b+' = '+final 60 | return final 61 | 62 | 63 | def multi_str2(a,b): 64 | orig_a = a; orig_b = b 65 | a = map(int, a[::-1]) 66 | b = map(int, b[::-1]) 67 | # multiply into digit by digit 68 | final = '' 69 | carry = 0 70 | ### IMPORTANT PART ### 71 | for s in range(len(a)+len(b)-1): 72 | for i in range(len(a)): 73 | j = s-i 74 | if 0 <= j <= len(b)-1: 75 | #print i,j 76 | carry += a[i]*b[j] 77 | final += str(carry % 10) 78 | carry //= 10 79 | 80 | if carry > 0: final += str(carry) 81 | final = final[::-1] 82 | print orig_a + ' * '+ orig_b +' = '+final 83 | return final 84 | 85 | 86 | if __name__ == '__main__': 87 | multi_str("1999", "0") 88 | multi_str("989", "120") 89 | multi_str("9999999", "9999999") 90 | multi_str2("1999", "0") 91 | multi_str2("989", "120") 92 | multi_str2("9999999", "9999999") 93 | 94 | 95 | -------------------------------------------------------------------------------- /substr_concat_words.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Substring with Concatenation of All Words 4 | You are given a string, S, and a list of words, L, that are all of the same length. Find all starting indices of substring(s) in S that is a concatenation of each word in L exactly once and without any intervening characters. 5 | 6 | For example, given: 7 | S: "barfoothefoobarman" 8 | L: ["foo", "bar"] 9 | You should return the indices: [0,9]. 10 | (order does not matter). 11 | ''' 12 | from __future__ import division 13 | import random 14 | 15 | 16 | # Naive, O(len(S)*len(L)*len(word)) 17 | def concat_words(S, L): 18 | k = len(L[0]) 19 | rets = [] 20 | for i in range(len(S)-k+1): 21 | words = set(L) 22 | start = i 23 | while words: 24 | if S[start:start+k] in words: 25 | words.remove(S[start:start+k]) 26 | start += k 27 | else: 28 | break 29 | if not words: rets.append(i) 30 | return rets 31 | 32 | 33 | # check concatenation at 34 | # first 0, k, 2k, ..., n-1; 35 | # then 1, k+1, 2k+1, ..., n-1; 36 | # then 2, k+2, 2k+2, ..., n-1, etc.; 37 | # until k-1, 2k-1, 3k-1, ..., n-1. 38 | def concat_words2(S,L): 39 | k = len(L[0]) 40 | rets = [] 41 | for start in range(k): 42 | matched = [] 43 | unmatched = set(L) 44 | for i in range(start, len(S)-k+1, k): 45 | # Shift left for k pos 46 | # benefit from the previous match 47 | if matched: 48 | unmatched.add(matched[0]) 49 | matched = matched[1:] 50 | 51 | # Consider substring starting at i pos 52 | pos = i 53 | while unmatched: 54 | word = S[pos:pos+k] 55 | if word in unmatched: # Continue when matched. 56 | unmatched.remove(word) 57 | matched.append(word) 58 | else: 59 | break # Leave when unmatched. 60 | pos += k 61 | if not unmatched: 62 | rets.append(i) 63 | else: 64 | # clear; prepare for re-matching at the next pos 65 | matched = [] 66 | unmatched = set(L) 67 | print rets 68 | return rets 69 | 70 | 71 | if __name__ == '__main__': 72 | print concat_words("barfoothefoobarman", ["foo","bar"]) 73 | print concat_words("skyesskikeyyesskiandkeyskiyes", ["key","ski","yes"]) 74 | print concat_words2("barfoothefoobarman", ["foo","bar"]) 75 | print concat_words2("skyesskikeyyesskiandkeyskiyes", ["key","ski","yes"]) 76 | 77 | 78 | -------------------------------------------------------------------------------- /letter_comb_phone.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Letter Combinations of a Phone Number 4 | Given a digit string, return all possible letter combinations that the number could represent. 5 | 6 | A mapping of digit to letters: 7 | 1() 2(abc) 3(def) 8 | 4(ghi) 5(jkl) 6(mno) 9 | 7(pgrs) 8(tuv) 9(wxyz) 10 | 11 | Input:Digit string "23" 12 | Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. 13 | ''' 14 | from __future__ import division 15 | import random 16 | 17 | num2lett = { 18 | 1:'', 2:'abc',3:'def', 19 | 4:'ghi',5:'jkl',6:'mno', 20 | 7:'pqrs',8:'tuv',9:'wxyz', 21 | 0:' '} 22 | 23 | def letter_comb_phone(num2lett, digits): 24 | ret = [''] 25 | for d in digits: 26 | if (not d.isdigit()) or (int(d) not in num2lett): return [] 27 | cands = list(num2lett[int(d)]) 28 | ret = [x+y for x in ret for y in cands] 29 | return ret 30 | 31 | 32 | 33 | ''' What if we have a dictionary? ''' 34 | def get_cands(num2lett, digits): 35 | ret = [''] 36 | for d in digits: 37 | if (not d.isdigit()) or (int(d) not in num2lett): return [] 38 | cands = list(num2lett[int(d)]) 39 | ret = [x+y for x in ret for y in cands] 40 | return ret 41 | 42 | def phone_mapping(num2lett, dictionary, number): 43 | if len(number) == 0: yield [] 44 | else: 45 | n = len(number) 46 | for i in range(1,n+1): 47 | sub = number[:i] 48 | words = [c for c in get_cands(num2lett, sub) if c in dictionary] 49 | if not words: continue 50 | for w in words: 51 | for other_words in phone_mapping(num2lett, dictionary, number[i:]): 52 | yield [w] + other_words 53 | 54 | 55 | ''' How to optimize it? Mometization ''' 56 | memo = {} 57 | def phone_mapping2(num2lett, dictionary, number, words): 58 | global memo 59 | 60 | if len(number) == 0: return True 61 | 62 | if number in memo: return memo[number] 63 | 64 | n = len(number) 65 | can_split = False 66 | for i in range(1,n+1): 67 | sub = number[:i] 68 | cands = [c for c in get_cands(num2lett, sub) if c in dictionary] 69 | if not cands: continue 70 | if phone_mapping2(num2lett, dictionary, number[i:], words): 71 | words.append(cands[0]) 72 | can_split = True 73 | memo[number] = True 74 | break 75 | memo[number] = can_split 76 | return can_split 77 | 78 | 79 | if __name__ == '__main__': 80 | #print letter_comb_phone("23052") 81 | #print letter_comb_phone("47825") 82 | words = [] 83 | phone_mapping2(num2lett, set(['a','aa','aaa','aaaa']), '22223', words) 84 | print memo 85 | print words 86 | 87 | 88 | -------------------------------------------------------------------------------- /merge_intervals.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Merge Intervals 4 | Given a collection of intervals, merge all overlapping intervals. 5 | For example, 6 | Given [1,3],[2,6],[8,10],[15,18], 7 | return [1,6],[8,10],[15,18]. 8 | ''' 9 | from __future__ import division 10 | import random 11 | 12 | 13 | def is_overlapped(intv1, intv2): 14 | return intv2[0]<=intv1[0]<=intv2[1] or intv2[0]<=intv1[1]<=intv2[1] 15 | 16 | 17 | def merged_intv(intv1, intv2): 18 | return [min(intv1[0], intv2[0]), max(intv1[1], intv2[1])] 19 | 20 | 21 | # Naive: 22 | # start from the first interval and compare it with all other intervals for overlapping, if it overlaps with any other interval, then remove the other interval from list and merge the other into the first interval. 23 | # Repeat the same steps for remaining intervals after first. 24 | # O(n^2) 25 | def merge_intervals(intvs): 26 | merged_intvs = [] 27 | i = 0 28 | while i < len(intvs): 29 | cur = intvs[i] 30 | merged_indices = [] 31 | for j in range(i+1, len(intvs)): # compared with other intervals 32 | other = intvs[j] 33 | if is_overlapped(cur, other): 34 | # has overlapping 35 | merged = merged_intv(cur, other) 36 | intvs[i] = merged 37 | cur = merged 38 | merged_indices.append(j) 39 | 40 | if merged_indices: 41 | # the current interval is changed! 42 | for idx in sorted(merged_indices, reverse=True): 43 | del intvs[idx] 44 | #print 'remove', merged_indices, intvs 45 | else: 46 | i += 1 47 | 48 | print intvs 49 | return intvs 50 | 51 | 52 | # Sorted it first based on the starting element 53 | # if intvs[i] doesn't overlap with intvs[i-1], then intvs[i+1] cannot overlap with intvs[i-1] because intvs[i+1][0] >= intvs[i][0]. 54 | # O(nlogn + n) 55 | def merge_intervals2(intvs): 56 | intvs = sorted(intvs, key=lambda x:x[0]) 57 | stack = [] 58 | for intv in intvs: 59 | if (not stack) or (not is_overlapped(intv, stack[-1])): 60 | stack.append(intv) 61 | else: 62 | other = stack.pop() 63 | merged = merged_intv(other, intv) 64 | stack.append(merged) 65 | print stack 66 | return stack 67 | 68 | 69 | if __name__ == '__main__': 70 | merge_intervals([[1,3],[8,10],[2,6],[15,18],[15,18]]) 71 | merge_intervals([[1,3],[8,11],[15,18],[2,9],[18,20]]) 72 | merge_intervals([[1,1],[0,0],[1,1],[0,0]]) 73 | 74 | merge_intervals2([[1,3],[8,10],[2,6],[15,18],[15,18]]) 75 | merge_intervals2([[1,3],[8,11],[15,18],[2,9],[18,20]]) 76 | merge_intervals2([[1,1],[0,0],[1,1],[0,0]]) 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /LCA.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Lowest common ancesters 4 | http://leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-search-tree.html 5 | http://leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html 6 | http://leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-ii.html 7 | ''' 8 | from __future__ import division 9 | import random 10 | from BinaryTree import Node, BST, root 11 | 12 | 13 | ### We traverse from the bottom, and once we reach a node which matches one of the two nodes, we pass it up to its parent. The parent would then test its left and right subtree if each contain one of the two nodes. If yes, then the parent must be the LCA and we pass its parent up to the root. If not, we pass the lower node which contains either one of the two nodes (if the left or right subtree contains either p or q), or NULL (if both the left and right subtree does not contain either p or q) up. 14 | # O(n) 15 | def lca(root, a, b): 16 | if not root: return None 17 | if root.value == a or root.value == b: return root 18 | left = lca(root.left, a, b) 19 | right = lca(root.right, a, b) 20 | if left and right: 21 | # a & b are on both sides 22 | return root 23 | else: 24 | # EITHER a/b is on one side 25 | # OR a/b is not in L&R subtrees 26 | return left if left else right 27 | 28 | 29 | ### With parent pointer 30 | # find the height h(a), h(b) 31 | # move the lower node b up by h(a)-h(b) steps 32 | # move a and b up together until a=b 33 | def lca_parent(root, node_a, node_b): 34 | h_a = find_height(root, node_a) 35 | h_b = find_height(root, node_b) 36 | if h_b > h_a: 37 | node_a, node_b = node_b, node_a 38 | h_a,h_b = h_b,h_a 39 | for _ in range(h_b - h_a): 40 | node_b = node_b.parent 41 | while node_a != node_b: 42 | node_a = node_a.parent 43 | node_b = node_b.parent 44 | return node_a 45 | 46 | def find_height(root, node): 47 | h = 0 48 | while node: 49 | node = node.parent 50 | h += 1 51 | return h 52 | 53 | 54 | # 1. Both nodes are to the left of the tree. 55 | # 2. Both nodes are to the right of the tree. 56 | # 3. One node is on the left while the other is on the right. 57 | # 4. When the current node equals to either of the two nodes, this node must be the LCA too. 58 | # O(logn) 59 | def lca_BST(root, a, b): 60 | while root: 61 | if a <= root.value <= b: 62 | return root 63 | elif min(a,b) < root.value: 64 | root = root.left 65 | elif max(a,b) > root.value: 66 | root = root.right 67 | return None 68 | 69 | 70 | if __name__ == '__main__': 71 | print lca_BST(BST, 1,3) 72 | print lca_BST(BST, 9,16) 73 | 74 | 75 | -------------------------------------------------------------------------------- /sym_tree.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Symmetric Tree 4 | Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). 5 | For example, this binary tree is symmetric: 6 | 1 7 | / \ 8 | 2 2 9 | / \ / \ 10 | 3 4 4 3 11 | But the following is not: 12 | 1 13 | / \ 14 | 2 2 15 | \ \ 16 | 3 3 17 | Note: Bonus points if you could solve it both recursively and iteratively. 18 | ''' 19 | from __future__ import division 20 | import random 21 | from BinaryTree import Node 22 | 23 | 24 | # Recursive: the left and right tree are same when 25 | # left and right children are swapped. 26 | def sym_tree_recur(root): 27 | left_tree = root.left 28 | right_tree = root.right 29 | return is_same_tree_sym(left_tree, right_tree) 30 | 31 | def is_same_tree_sym(root1, root2): 32 | # whether root is None 33 | if not root1 and not root2: return True 34 | elif not root1 or not root2: return False 35 | 36 | # Both roots have no child and values are same 37 | if not root1.left and not root2.left and \ 38 | not root1.right and not root2.right and \ 39 | root1.value == root2.value: return True 40 | 41 | # Roots have different #children 42 | if (root1.value != root2.value) or \ 43 | ((not root1.left)^(not root2.right)) or \ 44 | ((not root1.right)^(not root2.left)): return False 45 | 46 | left = is_same_tree_sym(root1.left, root2.right) \ 47 | if root1.left and root2.right \ 48 | else True 49 | right = is_same_tree_sym(root1.right, root2.left) \ 50 | if root1.right and root2.left \ 51 | else True 52 | return left and right 53 | 54 | 55 | ## Iterative: pre-order traversal of the left and right sub-trees 56 | # push in slightly different order for left and right trees. 57 | def sym_tree_iter(root): 58 | lstack = [root.left] 59 | rstack = [root.right] 60 | while lstack or rstack: 61 | l = lstack.pop() 62 | r = rstack.pop() 63 | if not l and not r: return True 64 | if not l or not r: return False 65 | if l.value != r.value: return False 66 | lstack.append(l.right) 67 | lstack.append(l.left) 68 | rstack.append(r.left) 69 | rstack.append(r.right) 70 | return True 71 | 72 | 73 | 74 | if __name__ == '__main__': 75 | root1 = Node(1, 76 | left=Node(2, left=Node(4), right=Node(3)), 77 | right=Node(2, left=Node(3), right=Node(4))) 78 | root2 = Node(1, 79 | left=Node(2, right=Node(3)), 80 | right=Node(2, right=Node(3))) 81 | 82 | print sym_tree_recur(root1) 83 | print sym_tree_recur(root2) 84 | 85 | print sym_tree_iter(root1) 86 | print sym_tree_iter(root2) 87 | -------------------------------------------------------------------------------- /str_to_int.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: atoi 4 | Implement atoi to convert a string to an integer. 5 | 6 | Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases. 7 | 8 | Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front. 9 | 10 | ----------------------------------------------------------------------- 11 | http://www.cplusplus.com/reference/cstdlib/atoi/: 12 | The function first discards as many whitespace characters (as in isspace) as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many base-10 digits as possible, and interprets them as a numerical value. 13 | 14 | The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function. 15 | 16 | If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed and zero is returned. 17 | 18 | If no valid conversion could be performed, a zero value is returned. If the correct value is out of the range of representable values, INT_MAX (2147483647) or INT_MIN (-2147483648) is returned. 19 | ''' 20 | from __future__ import division 21 | import random 22 | 23 | INT_MAX = 2147483647 24 | INT_MIN = -2147483648 25 | 26 | # remove white spaces 27 | # +/- followed by base-10 digits 28 | # other characters are ignored 29 | def atoi(s): 30 | s = s.strip() 31 | neg = False 32 | if s[0] == '-': 33 | neg = True 34 | s = s[1:] 35 | elif s[0] == '+': 36 | s = s[1:] 37 | 38 | digits = '' 39 | for ch in s: 40 | if ch.isdigit(): 41 | digits += ch 42 | else: 43 | if len(digits) == 0: return 0 44 | elif not neg and digits > '2147483647': return INT_MAX 45 | elif neg and digits > '2147483648': return INT_MIN 46 | else: 47 | number = int(digits) 48 | return -number if neg else number 49 | # leftover 50 | if not neg and digits > '2147483647': return INT_MAX 51 | elif neg and digits > '2147483648': return INT_MIN 52 | else: 53 | number = int(digits) 54 | return -number if neg else number 55 | 56 | 57 | if __name__ == '__main__': 58 | print atoi('-112ddfs') 59 | print atoi('12345') 60 | print atoi('+01') 61 | print atoi('+0.2312') 62 | print atoi('-1900.2312') 63 | print atoi('a') 64 | print atoi('21474836472147483647') 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /merge_lists.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | 6 | 7 | ''' 8 | Leetcode: Merge Two Sorted Lists 9 | Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists. ''' 10 | # O(n+m) 11 | def merge_two(A, B): 12 | merged = [] 13 | m = len(A); n = len(B) 14 | i = j = -1 15 | while True: 16 | if (j >= n-1) or (i+1 <= m-1 and A[i+1] <= B[j+1]): 17 | # go one step on list A 18 | i += 1 19 | merged.append(A[i]) 20 | else: 21 | j += 1 22 | merged.append(B[j]) 23 | if i == m-1 and j == n-1: 24 | break 25 | print A, B, '-->', merged 26 | return merged 27 | 28 | 29 | ''' 30 | Leetcode: Merge k Sorted Lists 31 | Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. ''' 32 | # O(kn) 33 | def merge_k(Ls): 34 | merged = [] 35 | k = len(Ls) 36 | frontiers = dict((i, -1) for i in range(k)) 37 | final_length = sum([len(l) for l in Ls]) 38 | print 'final length:', final_length 39 | while True: 40 | next = None 41 | for i in range(k): 42 | j = frontiers[i] 43 | if j >= len(Ls[i])-1: continue # has reached the last element 44 | if (next is None) or (Ls[i][j+1] < Ls[next][frontiers[next]+1]): 45 | next = i 46 | frontiers[next] += 1 47 | merged.append( Ls[next][frontiers[next]] ) 48 | if len(merged) == final_length: break 49 | 50 | print Ls, '-->', merged 51 | return merged 52 | 53 | 54 | ''' 55 | Leetcode: Merge Sorted Array 56 | Given two sorted integer arrays A and B, merge B into A as one sorted array. 57 | Note: You may assume that A has enough space to hold additional elements from B. The number of elements initialized in A and B are m and n respectively. ''' 58 | def merge_two_into_one(A, B): 59 | merged = [] 60 | m = len(A); n = len(B) 61 | A += [0]*n 62 | while n > 0: 63 | if m <= 0 or A[m-1] < B[n-1]: 64 | n -= 1 65 | A[n+m] = B[n] 66 | else: 67 | m -= 1 68 | A[n+m] = A[m] 69 | print B, 'merged into:', A 70 | return merged 71 | 72 | 73 | 74 | if __name__ == '__main__': 75 | merge_two([1,3,5,7], [2,3,4,5,6,7]) 76 | merge_two([4,5,6,7,8,9,10], [1,2,3]) 77 | merge_two([1,1,1,1], [2,2,2,2]) 78 | merge_two([0],[0,0]) 79 | print 80 | merge_k([[1,3,5,7], [2,3,4,5,6,7], [4,5,6,7,8,9,10], [1,2,3]]) 81 | merge_k([[1,1,1,1], [2,2,2,2],[0],[0,0],[-1,2,3]]) 82 | print 83 | merge_two_into_one([1,3,5,7], [2,3,4,5,6,7]) 84 | merge_two_into_one([4,5,6,7,8,9,10], [1,2,3]) 85 | merge_two_into_one([1,1,1,1], [2,2,2,2]) 86 | merge_two_into_one([0],[0,0]) 87 | 88 | -------------------------------------------------------------------------------- /3sum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | from __future__ import division 5 | import random 6 | 7 | 8 | ''' 9 | Leetcode: 3Sum 10 | 11 | Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. 12 | 13 | Note: 14 | Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ? b ? c) 15 | The solution set must not contain duplicate triplets. 16 | For example, given array S = {-1 0 1 2 -1 -4}, 17 | A solution set is: 18 | (-1, 0, 1) 19 | (-1, -1, 2) 20 | http://leetcode.com/2010/04/finding-all-unique-triplets-that-sums.html 21 | ''' 22 | # ~ O(n^2) 23 | def three_sum(s): 24 | s = sorted(s) # O(nlogn) 25 | output = set() 26 | for k in range(len(s)): 27 | target = -s[k] 28 | i,j = k+1, len(s)-1 29 | while i < j: 30 | sum_two = s[i] + s[j] 31 | if sum_two < target: 32 | i += 1 33 | elif sum_two > target: 34 | j -= 1 35 | else: 36 | output.add((s[k],s[i],s[j])) 37 | i += 1 38 | j -= 1 39 | return output 40 | 41 | 42 | ''' 43 | Leetcode: Two sum 44 | Given an array of integers, find two numbers such that they add up to a specific target number. 45 | The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based. 46 | You may assume that each input would have exactly one solution. 47 | Input: numbers={2, 7, 11, 15}, target=9 48 | Output: index1=1, index2=2 49 | ''' 50 | def two_sum(L, target): 51 | L = sorted(L) 52 | i = 0; j = len(L)-1 53 | while i < j: 54 | if L[i]+L[j] == target: 55 | return i+1, j+1 56 | elif L[i]+L[j] > target: 57 | j -= 1 58 | else: 59 | i += 1 60 | return -1,-1 61 | 62 | 63 | # O(n^(k-1)) 64 | def k_sum(s, k, target): 65 | s = sorted(s) # O(nlogn) 66 | if k == 0: 67 | yield [] 68 | 69 | elif k == 1: 70 | if target in set(s): yield [target] 71 | 72 | elif k == 2: 73 | i = 0; j = len(s)-1 74 | while i < j: 75 | sum_two = s[i] + s[j] 76 | if sum_two < target: i += 1 77 | elif sum_two > target: j -= 1 78 | else: 79 | yield [s[i], s[j]] 80 | i += 1 81 | j -= 1 82 | else: 83 | for i in range(len(s)): 84 | next_target = target - s[i] 85 | for p in k_sum(s[i+1:], k-1, next_target): 86 | yield [s[i]] + p 87 | 88 | 89 | if __name__ == '__main__': 90 | #print three_sum([-1, 0, 1, 2, -1, -4]) 91 | #for p in k_sum([1, 0, -1, 0, -2, 2, 3, 5, -3], 4, 0): print p 92 | print two_sum([2, 7, 11, 15, 3], 13) 93 | -------------------------------------------------------------------------------- /max_rect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Maximal Rectangle 4 | Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area. 5 | ''' 6 | from __future__ import division 7 | import random 8 | from collections import defaultdict 9 | 10 | 11 | def print_matrix(A, rows, cols): 12 | for i in range(rows): 13 | for j in range(cols): 14 | print A[i,j], 15 | print 16 | 17 | 18 | # (1) Populate a table H for max length of vertical 1's. For each H[i,j], it is the maximum length of vertically continuous 1's ended at M[i][j], i.e. H[i,j] = k, meaning that M[i][j-k+1 .. j] are all 1's. 19 | # (2) Apply histogram algorithm on each row to find the maximum rectangle in the row. 20 | def max_rect(M): 21 | rows = len(M) 22 | cols = len(M[0]) 23 | H = {} 24 | for j in range(cols): 25 | cont_one = 0 26 | for i in range(rows): 27 | cont_one = cont_one+1 if M[i][j] == 1 else 0 28 | H[i,j] = cont_one 29 | print "Vertical one's matrix:" 30 | print_matrix(H, rows, cols) 31 | 32 | # Find max rectangle under histogram in each row 33 | # x_1, x_2, ..., x_j --> maximize min{x_k, x_k+1, ..., x_k+n-1}*n 34 | # S(i) = the max rectangle that contains ai with ai as height, 35 | # maximum width of rectangle including that bar will be L+R+1, where: 36 | # L is number of adjacent bars to the left of ith bar and height greater than or 37 | # equal to h(i). 38 | # R is number of adjacent bars to the right of ith bar and height greater than or 39 | # equal to h(i). 40 | max_area = 0 41 | for i in range(rows): 42 | # scan i-th row: 43 | S = dict((j, H[i,j]) for j in range(cols)) 44 | # left --> right 45 | stack = [] 46 | for j in xrange(cols): 47 | while stack and H[i,stack[-1]] >= H[i,j]: 48 | stack.pop() # extend to the left 49 | start = stack[-1]+1 if stack else 0 50 | S[j] += (j-start)*H[i,j] 51 | stack.append(j) 52 | 53 | # right --> left 54 | stack = [] 55 | for j in reversed(xrange(cols)): 56 | while stack or H[i,stack[-1]] >= H[i,j]: 57 | stack.pop(j) # extend to the right 58 | end = stack[-1]-1 if stack else cols-1 59 | S[j] += (end-j)*H[i,j] 60 | stack.append(j) 61 | 62 | # Get max of this row 63 | print str(i)+'-th row:', [S[j] for j in range(cols)] 64 | max_area = max(max_area, max(S.values())) 65 | 66 | print max_area 67 | return max_area 68 | 69 | 70 | 71 | 72 | if __name__ == '__main__': 73 | M = [[0,0,1,1,1,0,1], 74 | [1,0,1,1,1,1,1], 75 | [0,0,1,1,1,0,1], 76 | [1,1,1,0,1,1,1], 77 | [0,0,0,1,1,1,1] 78 | ] 79 | print '\n'.join(map(str,M)) 80 | max_rect(M) 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /longest_substr_no_repeat.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Longest Substring Without Repeating Characters 4 | Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1. 5 | http://leetcode.com/2011/05/longest-substring-without-repeating-characters.html 6 | ''' 7 | from __future__ import division 8 | import random 9 | 10 | ### Naive, ~O(n(n-1)/2) 11 | def longest_substr_no_repeat(s): 12 | n = len(s) 13 | max_len = 0 14 | for i in range(n): 15 | cur_len = 1 # length of no-repeat substr starting at index i 16 | chars = set([s[i]]) 17 | for j in range(i+1, n): 18 | if s[j] in chars: 19 | max_len = max(cur_len, max_len) 20 | break 21 | else: 22 | cur_len += 1 23 | chars.add(s[j]) 24 | print i, '-', s[i], chars, cur_len, max_len 25 | max_len = max(cur_len, max_len) 26 | if max_len == n-i: return max_len # others cannot be longer 27 | return max_len 28 | 29 | 30 | ### DP: time ~ O(n); space ~ O(n) 31 | # L(i) = length of no-repeat substr starting at index i 32 | # L(i+1) = L(i) + 1 if last_seen[s[i+1]] <= i-L[i]; 33 | # i + 1 - last_seen[s[i+1]] 34 | def longest_substr_no_repeat2(s): 35 | last_seen = {s[0]:0} 36 | L = {0:1} 37 | for i in range(1,len(s)): 38 | if last_seen.get(s[i], -1) <= (i-1)-L[i-1]: 39 | L[i] = L[i-1] + 1 40 | else: 41 | L[i] = i - last_seen[s[i]] 42 | last_seen[s[i]] = i 43 | print 'last_seen:', last_seen 44 | print 'L{}:', L 45 | return max(L.values()) 46 | 47 | 48 | ### http://leetcode.com/2011/05/longest-substring-without-repeating-characters.html 49 | # use a cache to record existing characters 50 | def longest_substr_no_repeat3(s): 51 | n = len(s) 52 | max_len = i = j = 0 53 | exist = dict((ch,False) for ch in range(257)) # ascii code 54 | while j < n: 55 | if exist[ord(s[j])]: 56 | max_len = max(max_len, j-i) 57 | # move i until the duplicate s[j] is removed 58 | while s[i] != s[j]: 59 | exist[ord(s[i])] = False 60 | i += 1 61 | i += 1 62 | j += 1 63 | else: 64 | exist[ord(s[j])] = True 65 | j += 1 66 | # leftover 67 | max_len = max(max_len, n-i) 68 | return max_len 69 | 70 | 71 | if __name__ == '__main__': 72 | print longest_substr_no_repeat("abcabcbbecaf") 73 | print longest_substr_no_repeat("bbbbbb") 74 | print longest_substr_no_repeat("ababa") 75 | print longest_substr_no_repeat("aaaaabcdefgggggghijklxyzzzz") 76 | print 77 | print longest_substr_no_repeat2("abcabcbbecaf") 78 | print longest_substr_no_repeat2("bbbbbb") 79 | print longest_substr_no_repeat2("ababa") 80 | print longest_substr_no_repeat2("aaaaabcdefgggggghijklxyzzzz") 81 | 82 | 83 | -------------------------------------------------------------------------------- /search_2D_matrix.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Search a 2D Matrix 4 | Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: 5 | (1) Integers in each row are sorted from left to right. 6 | (2) The first integer of each row is greater than the last integer of the previous row. 7 | For example, 8 | Consider the following matrix: 9 | [ 10 | [ 1, 3, 5, 7], 11 | [10, 11, 16, 20], 12 | [23, 30, 34, 50] 13 | ] 14 | http://leetcode.com/2010/10/searching-2d-sorted-matrix.html 15 | http://leetcode.com/2010/10/searching-2d-sorted-matrix-part-ii.html 16 | http://leetcode.com/2010/10/searching-2d-sorted-matrix-part-iii.html 17 | ''' 18 | from __future__ import division 19 | import random 20 | 21 | # Solution#1 22 | # O(m+n) 23 | def search_matrix(M, val): 24 | m = len(M); n = len(M[0]) 25 | i = 0; j = n-1 26 | while i < m and j >= 0: 27 | if M[i][j] == val: return val, (i, j) 28 | elif M[i][j] < val: i+=1 29 | else: j-=1 30 | return None 31 | 32 | # Solution#2 Binary search 33 | # O(log m + log n) 34 | # Treat matrix as a one-dimensional array so we can do a binary search 35 | # (i,j) --> index: im + j 36 | def search_matrix_binary(M, val): 37 | m = len(M); n = len(M[0]) 38 | i = 0; j = m*n-1 39 | while j >= i: 40 | mid = (i+j)//2 41 | x, y = divmod(mid, m) 42 | if M[x][y] == val: return val, (x,y) 43 | elif M[x][y] < val: i=mid+1 44 | else: j=mid-1 45 | return None 46 | 47 | # Split the matrix into four small matrixs 48 | # search in the one that the target that falls inside the range 49 | # R1 | R2 50 | # ------- 51 | # R3 | R4 52 | # R1 min = (i_0, j_0), max = (i_mid-1, j_mid-1) 53 | # R2 min = (i_0, j_mid), max = (i_mid-1, j_1) 54 | # R3 min = (i_mid, j_0), max = (i_1, j_mid-1) 55 | # R4 min = (i_mid, j_mid), max = (i_1, j_1) 56 | def search_in_one_quad_matrix(M, val, i, j): 57 | print i, j 58 | if j[0] == j[1] and i[0] == i[1]: 59 | return M[i[0]][j[0]] == val 60 | if j[0] > j[1] and i[0] > i[1]: 61 | return False 62 | 63 | mid_i = (i[0]+i[1]+1)//2 64 | mid_j = (j[0]+j[1]+1)//2 65 | founded = False 66 | for a,b,c,d in [(i[0],j[0],mid_i-1,mid_j-1), \ 67 | (i[0],mid_j,mid_i-1,j[1]), \ 68 | (mid_i,j[0],i[1],mid_j-1), \ 69 | (mid_i,mid_j,i[1],j[1])]: 70 | if M[a][b] <= val <= M[c][d]: 71 | #print 'search_in_one_quad_matrix(M, val', '(',a,c,')', '(',b,d,') )' 72 | founded |= search_in_one_quad_matrix(M, val, (a,c), (b,d)) 73 | return founded 74 | 75 | 76 | # Solution#3 Search in 1/4 sub-matrix 77 | # T(n) = T(n/4) + C 78 | # ~ O(log n) 79 | def search_matrix_quad(M, val): 80 | m = len(M); n = len(M[0]) 81 | i = (0,m-1); j = (0,n-1) 82 | return search_in_one_quad_matrix(M, val, i, j) 83 | 84 | 85 | if __name__ == '__main__': 86 | M = [[1, 3, 5, 7], 87 | [10, 11, 16, 20], 88 | [23, 30, 34, 50], 89 | [51, 100, 200, 300] 90 | ] 91 | print search_matrix(M,11) 92 | print search_matrix(M,150) 93 | 94 | print search_matrix_quad(M,11) 95 | print search_matrix_quad(M,150) 96 | 97 | 98 | -------------------------------------------------------------------------------- /sudoku_solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Sudoku Solver 4 | Write a program to solve a Sudoku puzzle by filling the empty cells. 5 | Empty cells are indicated by the character '.'. 6 | You may assume that there will be only one unique solution. 7 | ''' 8 | from __future__ import division 9 | import sys 10 | 11 | INVALID = 0 12 | 13 | # fill in (x,y) with val@ 14 | def check_conflict(M, x, y, val): 15 | # column 16 | for i in range(9): 17 | if M[i][y] != INVALID: 18 | if M[i][y] == val: 19 | return True 20 | # row 21 | for j in range(9): 22 | if M[x][j] != INVALID: 23 | if M[x][j] == val: 24 | return True 25 | # cubes 26 | for i in range((x//3)*3, (x//3)*3+3): 27 | for j in range((y//3)*3, (x//3)*3+3): 28 | if M[i][j] != INVALID: 29 | if M[i][j] == val: 30 | return True 31 | return False 32 | 33 | 34 | def sudoku_fill_one(M, empty, rows, cols, cubes): 35 | print len(empty), 'to fill' 36 | # if no cell to fill 37 | if len(empty) == 0: return True 38 | i,j = empty[0] 39 | 40 | # need to fill in 41 | occupied = rows[i] | cols[j] | cubes[i//3,j//3] 42 | cands = set(range(1,10)) - occupied 43 | if not cands: return False 44 | 45 | for c in cands: 46 | #print 'Fill', c, 'in (%d,%d).' % (i,j) 47 | M[i][j] = c 48 | rows[i].add(c) 49 | cols[j].add(c) 50 | cubes[i//3,j//3].add(c) 51 | if sudoku_fill_one(M, empty[1:], rows, cols, cubes): 52 | return True 53 | # trace back 54 | M[i][j] = INVALID 55 | rows[i].remove(c) 56 | cols[j].remove(c) 57 | cubes[i//3,j//3].remove(c) 58 | 59 | 60 | def sudoku_solver(M): 61 | # keep a set of elements for each row, column and cube 62 | # rows[i] 63 | rows = dict( \ 64 | (i, set([M[i][j] for j in range(9) if M[i][j] != INVALID])) \ 65 | for i in range(9)) 66 | # cols[j] 67 | cols = dict( \ 68 | (j, set([M[i][j] for i in range(9) if M[i][j] != INVALID])) \ 69 | for j in range(9)) 70 | # cubes[i//3, j//3] 71 | cubes = dict(\ 72 | ((i,j), set([M[x][y] \ 73 | for x in range(i*3,i*3+3) \ 74 | for y in range(j*3,j*3+3) \ 75 | if M[x][y] != INVALID])\ 76 | ) for i in range(3) for j in range(3)) 77 | # empty cells 78 | empty = [(i,j) for i in range(9) for j in range(9) if M[i][j] == INVALID] 79 | 80 | print rows 81 | print cols 82 | print cubes 83 | print empty 84 | sudoku_fill_one(M, empty, rows, cols, cubes) 85 | print '\n'.join(map(str,M)) 86 | 87 | 88 | if __name__ == '__main__': 89 | M = [[5,3,0,0,7,0,0,0,0], 90 | [6,0,0,1,9,5,0,0,0], 91 | [0,9,8,0,0,0,0,6,0], 92 | [8,0,0,0,6,0,0,0,3], 93 | [4,0,0,8,0,3,0,0,1], 94 | [7,0,0,0,2,0,0,0,6], 95 | [0,6,0,0,0,0,2,8,0], 96 | [0,0,0,4,1,9,0,0,5], 97 | [0,0,0,0,8,0,0,7,9]] 98 | sudoku_solver(M) 99 | 100 | 101 | -------------------------------------------------------------------------------- /n_queens.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | 6 | 7 | ''' 8 | Leetcode: N-Queens 9 | The n-queens puzzle is the problem of placing n queens on an nxn chessboard such that no two queens attack each other. 10 | 11 | Given an integer n, return all distinct solutions to the n-queens puzzle. 12 | Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively. 13 | 14 | For example, 15 | There exist two distinct solutions to the 4-queens puzzle: 16 | [ 17 | [".Q..", // Solution 1 18 | "...Q", 19 | "Q...", 20 | "..Q."], 21 | 22 | ["..Q.", // Solution 2 23 | "Q...", 24 | "...Q", 25 | ".Q.."] 26 | ]''' 27 | 28 | 29 | def translate_cols(cols, n): 30 | solutions = [ 31 | ['.'*c+'Q'+'.'*(n-c-1) for c in col] 32 | for col in cols 33 | ] 34 | return solutions 35 | 36 | 37 | def print_solutions(sols): 38 | for sol in sols: 39 | for row in sol: 40 | print row 41 | print 42 | 43 | 44 | # Given the col positions, whether (i,j) conflicts with any existing queen 45 | def check_conflict(cols, n, i, j): 46 | # check column 47 | if j in set(cols): return True 48 | # check diagonals 49 | x, y = i-1, j-1 50 | while x >= 0 and y >= 0: 51 | if cols[x] == y: return True 52 | x, y = x-1, y-1 53 | x, y = i-1, j+1 54 | while x >= 0 and y <= n-1: 55 | if cols[x] == y: return True 56 | x, y = x-1, y+1 57 | return False 58 | 59 | 60 | # cols = [col_0, col_1, ..., col_n-1] 61 | # Queen is put on row i, col[i] 62 | # Currently there are len(cols) row 63 | def n_queens_place(cols, n, rets): 64 | if len(cols) == n: 65 | # has finished placing queens 66 | rets.append(cols) 67 | else: 68 | for j in range(n): 69 | if not check_conflict(cols, n, len(cols), j): 70 | n_queens_place(cols+[j], n, rets) 71 | 72 | 73 | def n_queens(n): 74 | rets = []; cols = [] 75 | n_queens_place(cols, n, rets) 76 | sols = translate_cols(rets, n) 77 | print_solutions(sols) 78 | print '#Solutions:', len(sols) 79 | 80 | 81 | ''' 82 | Leetcode: N-Queens II 83 | Follow up for N-Queens problem. Now, instead outputting board configurations, return the total number of distinct solutions. 84 | http://www.matrix67.com/blog/archives/266 85 | ''' 86 | # row, ld, rd are three bitmap showing which bits have been taken before 87 | 88 | def n_queens2(n, row, ld, rd): 89 | global counter 90 | FULL = 1 << n - 1 91 | if row != FULL: 92 | pos = FULL & ~(row | ld | rd) 93 | #print bin(row), bin(ld), bin(rd), '-->', bin(pos) 94 | while pos > 0: 95 | # go through all non-zero digit 96 | p = pos & (~pos + 1) # get the right-most 1. 97 | pos = pos - p # remove the right-most available pos. 98 | n_queens2(n, row+p, (ld+p)<<1, (rd+p)>>1) 99 | else: 100 | counter += 1 101 | 102 | 103 | if __name__ == '__main__': 104 | n = 12; counter = 0 105 | 106 | n_queens(n) 107 | n_queens2(n,0,0,0) 108 | print counter 109 | -------------------------------------------------------------------------------- /flat_tree_to_llist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Flatten Binary Tree to Linked List 4 | Given a binary tree, flatten it to a linked list in-place. 5 | For example, 6 | Given 7 | 1 8 | / \ 9 | 2 5 10 | / \ \ 11 | 3 4 6 12 | The flattened tree should look like: 13 | 1 14 | \ 15 | 2 16 | \ 17 | 3 18 | \ 19 | 4 20 | \ 21 | 5 22 | \ 23 | 6 24 | If you notice carefully in the flattened tree, 25 | each node's right child points to the next node of a pre-order traversal. 26 | ''' 27 | from __future__ import division 28 | import random 29 | from BinaryTree import Node, root 30 | 31 | 32 | ### In-order traversal without using recursion or stack, in place 33 | ### (Morris traversal) 34 | # 1. cur = root 35 | # 2. if cur has no left-child 36 | # 2.1 print cur.value 37 | # 2.2 cur --> cur.right 38 | # 3. else: 39 | # 3.1 cur --> the right most child of the left subtree 40 | # 3.2 cur --> cur.left 41 | def morris_traversal(root): 42 | cur = root 43 | while cur: 44 | if cur.left is not None: 45 | rightmost_in_left = cur.left 46 | while rightmost_in_left.right: 47 | rightmost_in_left = rightmost_in_left.right 48 | rightmost_in_left.right = cur 49 | cur_left = cur.left 50 | cur.left = None 51 | cur = cur_left 52 | else: # visit right child 53 | # no left child, it is the turn to visit the root! 54 | print cur.value, 55 | cur = cur.right 56 | 57 | 58 | # For each node: 59 | # 1. cur = root 60 | # 2. visit cur 61 | # 3. if cur has no left-child: 62 | # 3.1 cur = cur.right 63 | # 4. else: 64 | # 4.1 move cur's right-child to the rightmost child of its left subtree 65 | # 4.2 cur = cur.left 66 | def inplace_preorder_traversal(root): 67 | cur = root 68 | while cur: 69 | print cur.value, 70 | if cur.left: 71 | if cur.right: 72 | rightmost_in_left = cur.left 73 | while rightmost_in_left.right: 74 | rightmost_in_left = rightmost_in_left.right 75 | rightmost_in_left.right = cur.right 76 | cur.right = None 77 | cur = cur.left 78 | else: 79 | cur = cur.right 80 | 81 | 82 | def flatten(root): 83 | cur = root 84 | # pre-order in-place traversal 85 | while cur: 86 | #print cur.value, 87 | if cur.left: 88 | if cur.right: 89 | rightmost_in_left = cur.left 90 | while rightmost_in_left.right: 91 | rightmost_in_left = rightmost_in_left.right 92 | rightmost_in_left.right = cur.right 93 | cur.right = None 94 | cur = cur.left 95 | else: 96 | cur = cur.right 97 | print root 98 | # move all left child to be right child 99 | cur = root 100 | while cur: 101 | if cur.left: 102 | cur.right = cur.left 103 | cur.left = None 104 | cur = cur.right 105 | print root 106 | 107 | 108 | if __name__ == '__main__': 109 | print root 110 | flatten(root) 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /decode_ways.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Decode ways 4 | A message containing letters from A-Z is being encoded to numbers using the following mapping: 5 | 'A' -> 1 6 | 'B' -> 2 7 | ... 8 | 'Z' -> 26 9 | Given an encoded message containing digits, determine the total number of ways to decode it. 10 | 11 | For example, Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12). The number of ways decoding "12" is 2. 12 | ''' 13 | from __future__ import division 14 | import random 15 | 16 | # ord('A') = 65; ord('a') = 97 17 | # mapping = dict((code-64, chr(code)) for code in range(ord('A'), ord('Z')+1)) 18 | def decode_ways(msg): 19 | if msg == '': return 1 20 | if len(msg) == 1 and int(msg) > 0: return 1 21 | if len(msg) == 1 and int(msg) == 0: return 0 22 | first_one = int(msg[0]) 23 | first_two = int(msg[:2]) 24 | x = decode_ways(msg[1:]) if 1 <= first_one <= 9 else 0 25 | y = decode_ways(msg[2:]) if 1 <= first_two <= 26 else 0 26 | return x+y 27 | 28 | 29 | ## DP: 30 | # S[i] = #decoding ways for msg[:i], 0 <= i <= n 31 | # S[i] = S[i-1] (if msg[i-1] > 0) + S[i-2] (if msg[i-2:i] between 1 and 26) 32 | def decode_ways_iter(msg): 33 | S={} 34 | S[0] = 1 35 | S[1] = 1 if msg[0] != '0' else 0 36 | for i in range(2,len(msg)+1): 37 | x = S[i-1] if msg[i-1] != '0' else 0 38 | y = S[i-2] if 1 <= int(msg[i-2:i]) <= 26 else 0 39 | S[i] = x + y 40 | return S[len(msg)] 41 | 42 | 43 | def decode_ways_content(msg, mapping): 44 | if len(msg) == 0: 45 | yield '' 46 | elif len(msg) == 1 and int(msg) > 0: 47 | yield mapping[int(msg)] 48 | else: 49 | first_one = int(msg[0]) 50 | if 1 <= first_one <= 9: 51 | for d in decode_ways_content(msg[1:], mapping): 52 | yield mapping[first_one] + d 53 | first_two = int(msg[:2]) 54 | if 1 <= first_two <= 26: 55 | for d in decode_ways_content(msg[2:], mapping): 56 | yield mapping[first_two] + d 57 | 58 | 59 | def decode_ways_content_iter(msg, mapping): 60 | S={} 61 | S[0] = [''] 62 | S[1] = [mapping[int(msg[0])]] if msg[0] != '0' else [] 63 | for i in range(2, len(msg)+1): 64 | S[i] = [] 65 | first_one = int(msg[i-1:i]) 66 | first_two = int(msg[i-2:i]) 67 | if first_one > 0: 68 | for prev in S[i-1]: 69 | S[i].append( prev+mapping[first_one] ) 70 | if 1 <= first_two <= 26: 71 | for prev in S[i-2]: 72 | S[i].append( prev+mapping[first_two] ) 73 | return S[len(msg)] 74 | 75 | 76 | if __name__ == '__main__': 77 | mapping = {} 78 | for i, code in enumerate(range(ord('A'), ord('Z')+1)): 79 | mapping[i+1] = chr(code) 80 | 81 | print decode_ways('00') 82 | print decode_ways('1201200') 83 | print decode_ways('12302415') 84 | 85 | print decode_ways_iter('0') 86 | print decode_ways_iter('00') 87 | print decode_ways_iter('120') 88 | print decode_ways_iter('12302415') 89 | 90 | for d in decode_ways_content('00', mapping): print d 91 | for d in decode_ways_content('12302415', mapping): print d 92 | 93 | print '00:' 94 | for d in decode_ways_content_iter('00', mapping): print d 95 | print '12302415:' 96 | for d in decode_ways_content_iter('12302415', mapping): print d 97 | 98 | 99 | -------------------------------------------------------------------------------- /surrounded_reg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Surrounded Regions 4 | Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A region is captured by flipping all 'O's into 'X's in that surrounded region . 5 | 6 | For example, 7 | X X X X 8 | X O O X 9 | X X O X 10 | X O X X 11 | 12 | After running your function, the board should be: 13 | X X X X 14 | X X X X 15 | X X X X 16 | X O X X 17 | ''' 18 | from __future__ import division 19 | import random 20 | 21 | # Naive 22 | # grow a set of 'O', add all neighboring 'O' 23 | # flip it all 'O' in the set have neighbors. 24 | # ~O(n^2+n) 25 | def surrounded_region(M): 26 | m = len(M); n = len(M[0]) 27 | # Detect all connected regions 28 | regions = [] 29 | for i in range(m): 30 | for j in range(n): 31 | if M[i][j] == 'O': 32 | find_reg = False 33 | for reg in regions: 34 | if (i+1,j) in reg or (i-1,j) in reg or (i,j-1) in reg or (i,j+1) in reg: 35 | reg.add((i,j)) 36 | find_reg = True 37 | if not find_reg: 38 | regions.append( set([(i,j)]) ) 39 | 40 | # Scan all regions 41 | for reg in regions: 42 | surrounded = True 43 | for i,j in reg: 44 | if i==0 or i==m-1 or j==0 or j==n-1: 45 | # Any element is on the boundary 46 | surrounded = False 47 | break 48 | if surrounded: 49 | # replace 'O' with 'X'. 50 | for i,j in reg: 51 | M[i][j] = 'X' 52 | 53 | print '\n'.join(map(str,M)), '\n' 54 | return M 55 | 56 | 57 | # Starting from 'O' on the boundary and flip all connected 'O' to 'T' 58 | # Go through again flip everything other than 'T'-->'X' and flip 'T'-->'O' 59 | # O(n) 60 | def BFS_marker(M, i, j): 61 | m = len(M); n = len(M[0]) 62 | # BFS uses queue; DFS uses stack 63 | queue = [(i,j)] 64 | while queue: 65 | x,y = queue.pop(0) 66 | M[x][y] = 'T' 67 | if x-1>=0 and M[x-1][y] == 'O': queue.append((x-1,y)) 68 | if x+1<=m-1 and M[x+1][y] == 'O': queue.append((x+1,y)) 69 | if y-1>=0 and M[x][y-1] == 'O': queue.append((x,y-1)) 70 | if y+1<=n-1 and M[x][y+1] == 'O': queue.append((x,y+1)) 71 | 72 | 73 | def surrounded_region2(M): 74 | m = len(M); n = len(M[0]) 75 | # BFS uses queue; DFS uses stack 76 | queue = [] 77 | for i in range(m): 78 | if M[i][0] == 'O': BFS_marker(M,i,0) 79 | if M[i][n-1] == 'O': BFS_marker(M,i,n-1) 80 | for j in range(n): 81 | if M[0][j] == 'O': BFS_marker(M,0,j) 82 | if M[m-1][j] == 'O': BFS_marker(M,m-1,j) 83 | 84 | print '\n'.join(map(str,M)), '\n' 85 | 86 | for i in range(m): 87 | for j in range(n): 88 | if M[i][j] == 'T': M[i][j] = 'O' 89 | else: M[i][j] = 'X' 90 | 91 | print '\n'.join(map(str,M)), '\n' 92 | return M 93 | 94 | 95 | if __name__ == '__main__': 96 | M = [['X','X','X','X','O','X'], 97 | ['X','O','O','X','X','X'], 98 | ['X','X','O','X','O','X'], 99 | ['X','O','X','O','O','O'], 100 | ['X','X','X','X','O','O']] 101 | print '\n'.join(map(str,M)), '\n' 102 | 103 | surrounded_region2(M) 104 | 105 | -------------------------------------------------------------------------------- /popu_next_right_pointer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | from BinaryTree import Node as TreeNode 6 | 7 | class Node(TreeNode): 8 | def __init__(id=0, 9 | left=None, right=None, 10 | value=None, parent=None, 11 | next=None): 12 | TreeNode.__init__(self, id, left, right, value, parent) 13 | self.next = next # next right child on the same level 14 | 15 | ''' 16 | Leetcode: Populating Next Right Pointers in Each Node 17 | Given a binary tree 18 | struct TreeLinkNode { 19 | TreeLinkNode *left; 20 | TreeLinkNode *right; 21 | TreeLinkNode *next; 22 | } 23 | Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL. 24 | Initially, all next pointers are set to NULL. 25 | 26 | Note: 27 | !!!! You may only use constant extra space !!!! 28 | You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children). 29 | For example, 30 | Given the following perfect binary tree, 31 | 1 32 | / \ 33 | 2 3 34 | / \ / \ 35 | 4 5 6 7 36 | After calling your function, the tree should look like: 37 | 1 -> NULL 38 | / \ 39 | 2 -> 3 -> NULL 40 | / \ / \ 41 | 4->5->6->7 -> NULL 42 | ''' 43 | def populate_next_right(root): 44 | leftmost_node = root 45 | while left_node: 46 | across = leftmost_node 47 | while across: 48 | # left child --> right child 49 | if across.left: 50 | across.left.next = across.right 51 | # right child --> next node's left child 52 | if across.right and across.next: 53 | across.right.next = across.next.left 54 | across = across.next 55 | leftmost_node = leftmost_node.left 56 | 57 | 58 | ''' 59 | What if the given tree could be any binary tree? 60 | Would your previous solution still work? 61 | 62 | Note: 63 | You may only use constant extra space. 64 | For example, Given the following binary tree, 65 | 1 66 | / \ 67 | 2 3 68 | / \ \ 69 | 4 5 7 70 | After calling your function, the tree should look like: 71 | 1 -> NULL 72 | / \ 73 | 2 -> 3 -> NULL 74 | / \ \ 75 | 4-> 5 -> 7 -> NULL 76 | ''' 77 | def populate_next_right2(root): 78 | node = root 79 | while node: 80 | next_level_node = None # the first node of next level 81 | prev = None # previous node on the same level 82 | while node: 83 | # set up the next level starting point 84 | if not next_level_node: 85 | next_level_node = node.left if node.left else node.right 86 | # connect all nodes on this level 87 | if node.left: 88 | if prev: prev.next = node.left 89 | prev = node.left 90 | if node.right: 91 | if prev: prev.next = node.right 92 | prev = node.right 93 | node = node.next 94 | # turn to the next level: 95 | node = next_level_node 96 | 97 | 98 | if __name__ == '__main__': 99 | # populate_next_right() 100 | # populate_next_right2() 101 | pass 102 | 103 | 104 | -------------------------------------------------------------------------------- /text_justify.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Text Justification 4 | Given an array of words and a length L, format the text such that each line has exactly L characters and is fully (left and right) justified. You should pack your words in a greedy approach; that is, pack as many words as you can in each line. Pad extra spaces ' ' when necessary so that each line has exactly L characters. 5 | 6 | Extra spaces between words should be distributed as evenly as possible. If the number of spaces on a line do not divide evenly between words, the empty slots on the left will be assigned more spaces than the slots on the right. 7 | 8 | For the last line of text, it should be left justified and no extra space is inserted between words. 9 | 10 | For example, 11 | words: ["This", "is", "an", "example", "of", "text", "justification."] 12 | L: 16. 13 | Return the formatted lines as: 14 | [ 15 | "This is an", 16 | "example of text", 17 | "justification. " 18 | ] 19 | Note: Each word is guaranteed not to exceed L in length. 20 | 21 | Corner Cases: A line other than the last line might contain only one word. What should you do in this case? In this case, that line should be left-justified. 22 | ''' 23 | from __future__ import division 24 | import random 25 | 26 | def justification(words, L): 27 | lines = [] 28 | cur_words = []; cur_len = 0 29 | for w in words: 30 | if cur_len + 1 + len(w) > L: 31 | # cannot contain current words 32 | if len(cur_words) > 1: 33 | space, leftover = divmod(L-cur_len, len(cur_words)-1) 34 | space += 1 35 | line = cur_words[0] 36 | for cw in cur_words[1:]: 37 | if leftover > 0: 38 | line += ' '*(space+1) + cw 39 | leftover -= 1 40 | else: 41 | line += ' '*space + cw 42 | else: 43 | line = cur_words[0]+' '*(L-cur_len) 44 | lines.append(line) 45 | cur_words = [w] 46 | cur_len = len(w) 47 | else: 48 | cur_words.append(w) 49 | cur_len += 1+len(w) 50 | # last line 51 | if cur_words: 52 | line = ' '.join(cur_words) + ' '*(L-cur_len) 53 | lines.append(line) 54 | 55 | print '\n'.join(['"'+l+'"' for l in lines]) 56 | return lines 57 | 58 | 59 | if __name__ == '__main__': 60 | justification(["This", "is", "an", "example", "of", "text", "justification."], 16) 61 | justification(['Supervised', 'learning', 'is', 'the', 'machine', 'learning', 'task', 'of', 'inferring', 'a', 'function', 'from', 'labeled', 'training', 'data.', 'The', 'training', 'data', 'consist', 'of', 'a', 'set', 'of', 'training', 'examples.', 'In', 'supervised', 'learning', 'each', 'example', 'is', 'a', 'pair', 'consisting', 'of', 'an', 'input', 'object', 'typically', 'a', 'vector', 'and', 'a', 'desired', 'output', 'value', 'also', 'called', 'the', 'supervisory', 'signal.', 'A', 'supervised', 'learning', 'algorithm', 'analyzes', 'the', 'training', 'data', 'and', 'produces', 'an', 'inferred', 'function', 'which', 'can', 'be', 'used', 'for', 'mapping', 'new', 'examples', 'An', 'optimal', 'scenario', 'will', 'allow', 'for', 'the', 'algorithm', 'to', 'correctly', 'determine', 'the', 'class', 'labels', 'for', 'unseen', 'instances.', 'This', 'requires', 'the', 'learning', 'algorithm', 'to', 'generalize', 'from', 'the', 'training', 'data', 'to', 'unseen', 'situations', 'in', 'a', 'reasonable', 'way.'], 100) 62 | 63 | 64 | -------------------------------------------------------------------------------- /subsets.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | 6 | 7 | ''' 8 | Leetcode: Subsets 9 | Given a set of distinct integers, S, return all possible subsets. 10 | Note: 11 | Elements in a subset must be in non-descending order. 12 | The solution set must not contain duplicate subsets. 13 | For example, 14 | If S = [1,2,3], a solution is: 15 | [ 16 | [3], 17 | [1], 18 | [2], 19 | [1,2,3], 20 | [1,3], 21 | [2,3], 22 | [1,2], 23 | [] 24 | ] 25 | ''' 26 | def subsets_generator(S): 27 | if len(S) == 1: yield S 28 | else: 29 | for i in range(len(S)): 30 | ch = S[i] 31 | yield [ch] 32 | if S[i+1:]: 33 | for other in subsets_generator(S[i+1:]): 34 | yield [ch] + other 35 | 36 | 37 | def subsets(S): 38 | print '\nSubsets of', S 39 | S = sorted(S) 40 | for sset in subsets_generator(S): 41 | print sset 42 | print [] 43 | 44 | 45 | def subsets_iter(S): 46 | print '\nSubsets of', S 47 | S = sorted(S) 48 | ss = [] 49 | for ch in S: 50 | if ss: 51 | ss += [sset + [ch] for sset in ss] 52 | else: 53 | ss.append([]) 54 | ss.append([ch]) 55 | print ss 56 | return ss 57 | 58 | 59 | ''' 60 | Leetcode: Subsets || 61 | Given a collection of integers that might contain duplicates, S, return all possible subsets. 62 | Note: 63 | Elements in a subset must be in non-descending order. 64 | The solution set must not contain duplicate subsets. 65 | For example, 66 | If S = [1,2,2], a solution is: 67 | [ 68 | [2], 69 | [1], 70 | [1,2,2], 71 | [2,2], 72 | [1,2], 73 | [] 74 | ] 75 | ''' 76 | def subsets2_generator(S): 77 | if len(S) == 1: yield S 78 | else: 79 | checked = set() 80 | for i in range(len(S)): 81 | ch = S[i] 82 | if ch in checked: continue 83 | checked.add(ch) 84 | yield [ch] 85 | if S[i+1:]: 86 | for other in subsets2_generator(S[i+1:]): 87 | yield [ch] + other 88 | 89 | 90 | def subsets2(S): 91 | print '\nSubsets of', S 92 | S = sorted(S) 93 | for sset in subsets_generator2(S): 94 | print sset 95 | print [] 96 | 97 | 98 | # interesting solution! 99 | def subsets2_iter(S): 100 | print '\nSubsets of', S 101 | S = sorted(S) 102 | ss = [[]] 103 | start = 0 104 | for i in range(len(S)): 105 | cur_size = len(ss) 106 | for j in range(start, cur_size): 107 | sub = list(ss[j]) 108 | sub.append(S[i]) 109 | ss.append(sub) 110 | if i < len(S)-1 and S[i+1] == S[i]: 111 | # if next character is duplicated 112 | # only add it to the last few subarrays in the prev loop 113 | start = cur_size 114 | else: 115 | start = 0 116 | print ss 117 | return ss 118 | 119 | 120 | ## Print out all the subsets of an array without storing any subset. 121 | ## Index all the elements, and print out subsets according to binary numbers. 122 | def subset_binary(L): 123 | n = len(L) 124 | for b in range(2**n): 125 | selected_indices = [] 126 | i = 0 127 | while b > 0: 128 | b, bit = divmod(b, 2) 129 | if bit == 1: selected_indices.append(i) 130 | i += 1 131 | #print selected_indices 132 | yield [L[k] for k in selected_indices] 133 | 134 | 135 | if __name__ == '__main__': 136 | ''' 137 | subsets_iter([1,2,3]) 138 | subsets_iter([10,1,4,3]) 139 | subsets2_iter([1,2,2,2]) 140 | subsets2_iter([1,1,1,1]) 141 | ''' 142 | for x in subset_binary([1,2,3,4]): print x 143 | 144 | 145 | -------------------------------------------------------------------------------- /tree_depth.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | from BinaryTree import Node, SampleTreeRoot 6 | 7 | ''' 8 | Leetcode: Maximum Depth of Binary Tree 9 | Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. 10 | ''' 11 | def max_tree_depth_recur(root): 12 | if not root: 13 | return 0 14 | if not root.left and not root.right: 15 | return 1 16 | else: 17 | left_h = max_tree_depth_recur(root.left) if root.left else 0 18 | right_h = max_tree_depth_recur(root.right) if root.right else 0 19 | return max(left_h+1, right_h+1) 20 | 21 | 22 | # level-order traversal 23 | def max_tree_depth_iter(root): 24 | if not root: return 0 25 | cur_level = [root] # queue 26 | h = 0 27 | while cur_level: 28 | h += 1 29 | # traverse this level! 30 | next_level = [] 31 | for node in cur_level: 32 | if node.left: next_level.append(node.left) 33 | if node.right: next_level.append(node.right) 34 | cur_level = next_level 35 | return h 36 | 37 | 38 | ### post-order traversal; check the stack depth 39 | def max_tree_depth_iter2(root): 40 | if not root: return 0 41 | h = 0 42 | stack = [root] 43 | prev = None 44 | while stack: 45 | curr = stack[-1] 46 | if (not prev) or (prev.left == curr) or (prev.right == curr): 47 | if curr.left: stack.append(curr.left) 48 | elif curr.right: stack.append(curr.right) 49 | elif curr.left == prev: 50 | if curr.right: stack.append(curr.right) 51 | else: 52 | stack.pop() 53 | prev = curr 54 | h = max(h, len(stack)) 55 | return h 56 | 57 | 58 | ''' 59 | Leetcode: Minimum Depth of Binary Tree 60 | Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node. 61 | ''' 62 | def min_tree_depth_recur(root): 63 | if not root.left or not root.right: 64 | return 1 65 | else: 66 | left_dep = min_tree_depth_recur(root.left) 67 | right_dep = min_tree_depth_recur(root.right) 68 | return min(left_dep, right_dep)+1 69 | 70 | 71 | # level-order traversal 72 | def min_tree_depth_iter(root): 73 | if not root: return 0 74 | cur_level = [root] # queue 75 | h = 0 76 | while cur_level: 77 | h += 1 78 | # traverse this level! 79 | next_level = [] 80 | for node in cur_level: 81 | if not node.left or not node.right: 82 | return h 83 | else: 84 | next_level.append(node.left) 85 | next_level.append(node.right) 86 | cur_level = next_level 87 | return h 88 | 89 | 90 | ### post-order traversal 91 | def min_tree_depth_iter2(root): 92 | stack = [root] 93 | prev = None 94 | h = None 95 | while stack: 96 | curr = stack[-1] 97 | if (not prev) or (prev.left == curr) or (prev.right == curr): 98 | if curr.left: stack.append(curr.left) 99 | elif curr.right: stack.append(curr.right) 100 | elif (curr.left == prev): 101 | if curr.right: stack.append(curr.right) 102 | else: 103 | if not curr.left and not curr.right: # a leave node 104 | if not h: h = len(stack) 105 | else: h = min(h, len(stack)) 106 | stack.pop() 107 | prev = curr 108 | return h 109 | 110 | 111 | if __name__ == '__main__': 112 | print SampleTreeRoot 113 | print max_tree_depth_recur(SampleTreeRoot) 114 | print max_tree_depth_iter(SampleTreeRoot) 115 | print max_tree_depth_iter2(SampleTreeRoot) 116 | print 117 | print min_tree_depth_recur(SampleTreeRoot) 118 | print min_tree_depth_iter(SampleTreeRoot) 119 | print min_tree_depth_iter2(SampleTreeRoot) 120 | 121 | 122 | -------------------------------------------------------------------------------- /palin_partition.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import math 5 | from valid_palin import valid_palin 6 | 7 | ''' 8 | Leetcode: Palindrome partition I 9 | Given a string s, partition s such that every substring of the partition is a palindrome. Return all possible palindrome partitioning of s. 10 | 11 | For example, given s = "aaba", 12 | Return 13 | [ 14 | ["a","a","b","a"], 15 | ["aa","b","a"], 16 | ["a","aba"] 17 | ]''' 18 | memo_palin = {} 19 | def palin_partition(s): 20 | global memo_palin 21 | n = len(s) 22 | if n == 0: yield [] 23 | elif n == 1: yield [s] 24 | else: 25 | s = list(s) 26 | for i in range(n): 27 | first = s[:i+1] 28 | if first in memo_palin: 29 | # Use memotization to save time 30 | is_palin = memo_palin[first] 31 | else: 32 | is_palin = valid_palin(first) 33 | memo_pali[first] = is_palin 34 | if is_palin: 35 | for p in pali_partition(s[i+1:]): 36 | yield [first_sub] + p 37 | 38 | 39 | ''' 40 | Leetcode: Palindrome partition II 41 | Given a string s, partition s such that every substring of the partition is a palindrome. Return the minimum cuts needed for a palindrome partitioning of s. 42 | 43 | For example, given s = "aab", 44 | Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut. 45 | ''' 46 | memo_palin = {} 47 | def palin_partition_min_cut(s): 48 | global memo_palin 49 | n = len(s) 50 | if n == 0: yield [] 51 | elif n == 1: yield [s[0]] 52 | else: 53 | for i in range(n): 54 | first = s[:i+1] 55 | if first in memo_palin: 56 | # Use memotization to save time 57 | is_palin = memo_palin[first] 58 | else: 59 | is_palin = valid_palin(first) 60 | memo_palin[first] = is_palin 61 | if is_palin: 62 | min_cut = n-i 63 | min_p = None 64 | for p in palin_partition_min_cut(s[i+1:]): 65 | if len(p) < min_cut: 66 | min_cut = len(p) 67 | min_p = p 68 | yield [first] + min_p 69 | 70 | 71 | # DP? 72 | # palin(i,j) = True if s[i:j+1] is a palindrome 73 | # palin(i,j) = s[i] == s[j] and (j-i<2 or palin(i+1,j-1)) 74 | # cut(j) = minimum cut on s[:j+1] to produce a palindrome partition 75 | # cut(j) = min{cut(i-1)+1, cut(j)} if palin(i,j) == True 76 | def palin_min_cut(s): 77 | n = len(s) 78 | # single letter is a palinfrom 79 | palin = dict(((i,i), True) for i in range(n)) 80 | # cut between every consecutive letters 81 | cut = dict((i,i) for i in range(0,n)) 82 | cut[-1] = 0 83 | for k in xrange(1,n-1): 84 | for i in xrange(n): 85 | j = i+k 86 | if j >= n: continue 87 | print i,j 88 | if s[i] == s[j] and (j-i < 2 or palin[(i+1,j-1)]): 89 | palin[(i,j)] = True 90 | cut[j] = min(cut[j], cut[i-1]+1) 91 | else: 92 | palin[(i,j)] = False 93 | return cut[n-1]-1 94 | 95 | 96 | ################################################################# 97 | def is_palin(S): 98 | i = 0; j = len(S)-1 99 | while i <= len(S)-1 and j >= 0 and i < j: 100 | if S[i] == S[j]: i+=1; j -=1 101 | else: break 102 | return i >= j 103 | 104 | #cut(i) = the min cut for palin partitioning of L[:i] 105 | #cut(i) = min{cut(j)+1 (if L[j:i] is a palin for 0<=j L[i+1], it can be a potential left bar. 15 | # Try to find the first j > i and L[j] >= i, then i-->j is a container 16 | def trap_water(L): 17 | n = len(L) 18 | water = 0 19 | i = 0 20 | while i < n-1: 21 | if L[i] > L[i+1]: 22 | # may be a left bar 23 | j = i+2 24 | while j < n and L[j] < L[i]: j += 1 25 | if j < n: 26 | water += (j-i-1)*L[i] - sum(L[i+1:j]) 27 | i = j-1 28 | i += 1 29 | print water 30 | return water 31 | 32 | 33 | # Try to use stack 34 | # ~ O(n) 35 | def trap_water_stack(L): 36 | stack = [] 37 | water = 0 38 | for i in range(len(L)): 39 | if not stack or L[i] < L[stack[-1]]: 40 | # Push when empty stack or current element < stack top 41 | stack.append(i) 42 | else: 43 | prev = stack.pop() 44 | # When popping, add water whenever the left bar > right bar 45 | while stack and L[i] >= L[stack[-1]]: 46 | cur = stack.pop() 47 | if L[cur] > L[prev]: 48 | w = (i-cur-1)*(L[cur]-L[prev]) 49 | water += w 50 | prev = cur 51 | stack.append(i) 52 | 53 | print water 54 | return water 55 | 56 | 57 | ### O(n) solution. for each bar, find the max height bar on the left and right. then for this bar it can hold min(max_left, max_right) - height 58 | def trap_water_col(L): 59 | n = len(L) 60 | # find the max height on the left of each column 61 | maxL = {} 62 | cur_max = 0 63 | for i in xrange(n): 64 | maxL[i] = cur_max 65 | cur_max = max(cur_max, L[i]) 66 | # find the max height on the right of each column 67 | maxR = {} 68 | cur_max = 0 69 | for i in reversed(xrange(n)): 70 | maxR[i] = cur_max 71 | cur_max = max(cur_max, L[i]) 72 | water = 0 73 | for i in xrange(n): 74 | w = min(maxL[i], maxR[i]) - L[i] 75 | water += max(w, 0) 76 | print water 77 | return water 78 | 79 | 80 | ''' 81 | What if water is trapped in 2-D matrix! 82 | ''' 83 | ### For each cell (i,j), the max water it can trap is: 84 | ### min height{max height of cells up/down/left/right} - heigh(i,j) 85 | def trap_water_2D(M): 86 | m = len(M[0]); n = len(M) 87 | U, D, L, R = {}, {}, {}, {} 88 | # Max height of left and right cell for each entry 89 | for i in xrange(n): 90 | maxL = maxR = 0 91 | for j in xrange(m): 92 | L[i,j] = maxL 93 | maxL = max(maxL, M[i][j]) 94 | for j in reversed(xrange(m)): 95 | R[i,j] = maxR 96 | maxR = max(maxR, M[i][j]) 97 | # Max height of up/down-cell for each entry 98 | for j in xrange(m): 99 | maxU = maxD = 0 100 | for i in xrange(n): 101 | U[i,j] = maxU 102 | maxU = max(maxU, M[i][j]) 103 | for i in reversed(xrange(n)): 104 | D[i,j] = maxD 105 | maxD = max(maxD, M[i][j]) 106 | 107 | water = 0 108 | for i in xrange(n): 109 | for j in xrange(m): 110 | h = min(L[i,j], R[i,j], U[i,j], D[i,j]) 111 | if h > M[i][j]: water += h-M[i][j] 112 | print water 113 | return water 114 | 115 | 116 | if __name__ == '__main__': 117 | #trap_water([0,1,0,2,1,0,1,3,2,1,2,1,4,1]) 118 | #trap_water_stack([0,1,0,2,1,0,1,3,2,1,2,1,4,1]) 119 | #trap_water_col([0,1,0,2,1,0,1,3,2,1,2,1,4,1]) 120 | 121 | M = [[2,2,2,1,1,1,1], 122 | [2,0,2,1,1,3,1], 123 | [2,2,2,1,3,0,3], 124 | [1,1,3,3,3,3,3], 125 | [1,1,1,1,1,1,1]] 126 | trap_water_2D(M) 127 | 128 | -------------------------------------------------------------------------------- /largest_rectangle_under_hist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Find largest rectangle under given histogram 4 | ''' 5 | from __future__ import division 6 | import random 7 | 8 | # For each ai, we can determine 9 | # S(i) = the max rectangle that contains ai with ai as height, 10 | # maximum width of rectangle including that bar will be L+R+1, where: 11 | # L is number of adjacent bars to the left of ith bar and height greater than or equal to h(i). R is number of adjacent bars to the right of ith bar and height greater than or equal to h(i). 12 | 13 | # O(n) 14 | def largest_rectangle0(A): 15 | L, R = {}, {} 16 | # find Li: for i-th element in L, 17 | # Li is from i to its left, the first element <= A[i] 18 | stack = [0] 19 | for i in xrange(1,n): 20 | while stack and A[i] <= A[stack[-1]]: stack.pop() 21 | if stack: L[i] = i-stack[-1]-1 22 | else: L[i] = i 23 | stack.append(i) 24 | # find Ri: for i-th element in L, 25 | # Ri is from i to its right, the first element <= A[i] 26 | R = {n-1:0}; stack = [n-1] 27 | for i in reversed(xrange(n-1)): 28 | while stack and A[i] <= A[stack[-1]]: stack.pop() 29 | if stack: R[i] = stack[-1]-i-1 30 | else: R[i] = (n-1)-i 31 | stack.append(i) 32 | 33 | S = dict((i, A[i]*(L[i]+R[i]+1)) for i in range(len(a))) 34 | print 'L:', L 35 | print 'R:', R 36 | print S 37 | return max(S.values()) 38 | 39 | 40 | # O(n^2) 41 | def largest_rectangle1(a): 42 | S = {} 43 | for i in range(len(a)): 44 | # check Left width 45 | j = i 46 | while j > 0 and a[j] >= a[i]: j -= 1 47 | if a[j] < a[i]: j = j+1 48 | L = i-j 49 | # check right width 50 | j = i 51 | while j < len(a)-1 and a[j] >= a[i]: j += 1 52 | if a[j] < a[i]: j = j-1 53 | R = j-i 54 | S[i] = (L+R)*a[i] 55 | print a 56 | print S 57 | return max(S.values()) 58 | 59 | 60 | ### Use stack to track height and starting index 61 | # compare current height with previous one, pop out previous one is the current < previous, and compute the rectangle area. 62 | # Scan twice, left-->right than right-->left 63 | def largest_rectangle2(a): 64 | S = {} 65 | # left --> right 66 | stack = [] 67 | for i in xrange(len(a)): 68 | while stack: 69 | if a[i] < a[stack[-1]]: 70 | start_i = stack.pop() 71 | S[start_i] = a[start_i] * (i-1-start_i) 72 | else: 73 | break 74 | stack.append(i) 75 | while stack: 76 | start_i = stack.pop() 77 | S[start_i] = a[start_i] * (len(a)-1-start_i) 78 | 79 | # left --> right 80 | stack = [] 81 | for i in reversed(xrange(len(a))): 82 | while stack: 83 | if a[i] < a[stack[-1]]: 84 | start_i = stack.pop() 85 | S[start_i] += a[start_i] * (start_i-i-1) 86 | else: 87 | break 88 | stack.append(i) 89 | while stack: 90 | start_i = stack.pop() 91 | S[start_i] += a[start_i] * start_i 92 | print S 93 | return max(S.values()) 94 | 95 | 96 | ### DP: O(n^2) 97 | # h(i,j) = the maximum height of a rectangle under the bars from ai to aj. 98 | # h(i,j) = min{a_k for i<=k<=j} 99 | # h(i,j+1) = min{h(i,j), a(j)} 100 | def largest_rectangle3(a): 101 | n = len(a) 102 | h = {} 103 | for i in range(n): h[i,i] = a[i] 104 | for k in range(1,n): 105 | for i in range(n): 106 | j = i+k 107 | if j >= n: continue 108 | h[i,j] = min(h[i,j-1], a[j]) 109 | 110 | S = dict(((i,j), (j-i)*h[i,j]) for i,j in h) 111 | print S 112 | return max(S.values()) 113 | 114 | 115 | # left[i] is the most-left side column that i can extend to; 116 | # left[i] = max{j: h[j]i} + 1; 119 | #the rectangle area is calculated as: area[i] = (right[i]-left[i]-1) * h[i]; 120 | 121 | 122 | if __name__ == '__main__': 123 | a = [2,1,3,2,4,5,2,3,1] 124 | print largest_rectangle2(a) 125 | print largest_rectangle3(a) 126 | 127 | -------------------------------------------------------------------------------- /BinaryTree.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | from math import log10 5 | 6 | class Node(object): 7 | def __init__(self, value=0, 8 | left=None, right=None, 9 | id=None, parent=None): 10 | self.id = id 11 | self.left = left 12 | self.right = right 13 | self.value = value 14 | self.parent = parent 15 | 16 | def __str__(self): 17 | if self.left is None and self.right is None: 18 | return str(self.value) 19 | else: 20 | return '%s (%s, %s)' % ( 21 | str(self.value), 22 | str(self.left), 23 | str(self.right)) 24 | 25 | def __repr__(self): 26 | s = 'TreeNode Object (id=' + str(self.id) + \ 27 | ' value='+str(self.value)+')' 28 | return s 29 | 30 | def pretty_print(self): 31 | # get each levels 32 | level = [self] 33 | to_prints = [[self.value]] 34 | while True: 35 | is_all_none = True 36 | next_level = [] 37 | to_print = [] 38 | for n in level: 39 | if n is None: 40 | next_level += [None, None] 41 | to_print += ['#','#'] 42 | else: 43 | is_all_none = False 44 | next_level += [n.left, n.right] 45 | left_val = n.left.value if n.left and n.left.value else '#' 46 | right_val = n.right.value if n.right and n.right.value else '#' 47 | to_print += [left_val, right_val] 48 | if is_all_none: break 49 | level = next_level 50 | to_prints.append(to_print) 51 | 52 | #max_val_digits = max([max([len(str(v)) for v in r]) for r in to_prints]) 53 | #print max_val_digits 54 | 55 | to_prints = to_prints[:-1] # remove the last row with only '#' 56 | to_pretty_prints = [] 57 | to_prints.reverse() 58 | for i, row in enumerate(to_prints): 59 | row = map(str,row) 60 | #row = [' '*(max_val_digits-len(v))+v for v in row] 61 | sep = ' '*(2**(i+1) - 1) 62 | space = ' '*(2**i - 1) 63 | to_pretty_prints.insert(0, space + sep.join(row) + space) 64 | print '\n'.join(to_pretty_prints) 65 | 66 | 67 | root = Node(value=5, 68 | left=Node(value=4, 69 | left=Node(value=1, 70 | right=Node(value=2)) 71 | ), 72 | right=Node(value=8, 73 | left=Node(value=3), 74 | right=Node(value=4, 75 | left=Node(value=9), 76 | right=Node(value=1)) 77 | ) 78 | ) 79 | 80 | BST = Node(value=5, 81 | left=Node(value=2, 82 | left=Node(value=1, 83 | right=Node(value=1.5, 84 | left=Node(value=1.2))), 85 | right=Node(value=3) 86 | ), 87 | right=Node(value=9, 88 | left=Node(value=7), 89 | right=Node(value=15, 90 | right=Node(value=16) 91 | ) 92 | ) 93 | ) 94 | 95 | root_with_id = Node(id=0,value=-3, 96 | left=Node(id=1,value=-2, 97 | left=Node(id=3,value=3, 98 | left=Node(id=7,value=1, 99 | left=Node(id=11,value=4)), 100 | right=Node(id=8,value=1)), 101 | right=Node(id=4,value=-1, 102 | left=Node(id=9,value=4), 103 | right=Node(id=10,value=2)) 104 | ), 105 | right=Node(id=2,value=2, 106 | left=Node(id=5,value=-1), 107 | right=Node(id=6,value=3, 108 | right=Node(id=12,value=2)) 109 | ) 110 | ) 111 | 112 | 113 | if __name__ == '__main__': 114 | root.pretty_print() 115 | print 116 | BST.pretty_print() 117 | -------------------------------------------------------------------------------- /word_break.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | http://thenoisychannel.com/2011/08/08/retiring-a-great-interview-problem/ 4 | ''' 5 | from __future__ import division 6 | import random 7 | 8 | 9 | ''' 10 | Leetcode: Word Break 11 | Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words. 12 | For example, given 13 | s = "leetcode", 14 | dict = ["leet", "code"]. 15 | Return true because "leetcode" can be segmented as "leet code". 16 | ''' 17 | def wordbreak(s, words): 18 | if len(s) == 0: return True 19 | # Test all prefixes 20 | for i in range(1, len(s)+1): 21 | sub = s[:i] 22 | if not sub in words: continue 23 | if wordbreak(s[i:], words): 24 | return True 25 | return False 26 | 27 | 28 | ### DP? O(n^2) 29 | # cut(i) = s[:i] can be splitted 30 | # cut(i+1) = OR{cut(j) and s[j:i] is a word for 0 <= j < i} 31 | def wordbreak_DP(s, words): 32 | words = set(words) 33 | cut = {0: True} 34 | for i in range(1,len(s)+1): 35 | cut[i] = False 36 | for j in range(i): 37 | if cut[j] and s[j:i] in words: 38 | cut[i] = True 39 | break 40 | return cut[len(s)] 41 | 42 | 43 | memo = {} 44 | def wordbreak_memo(s, words): 45 | if s == '': return True 46 | global memo 47 | if s in memo: return memo[s] 48 | for i in range(1,len(s)+1): 49 | sub = s[:i] 50 | if not sub in words: continue 51 | if wordbreak_memo(s[i:], words): 52 | memo[s] = True#; print memo 53 | return True 54 | return False 55 | 56 | ''' 57 | Leetcode: Word Break II 58 | Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word. Return all such possible sentences. 59 | For example, given 60 | s = "catsanddog", 61 | dict = ["cat", "cats", "and", "sand", "dog"]. 62 | A solution is ["cats and dog", "cat sand dog"]. 63 | ''' 64 | # ~O(exponential) 65 | def wordbreak2_generator(s, words): 66 | if len(s) == 0: yield [] 67 | else: 68 | # Test all prefixes 69 | for i in range(1, len(s)+1): 70 | sub = s[:i] 71 | if not sub in words: continue 72 | for others in wordbreak2_generator(s[i:], words): 73 | yield [sub] + others 74 | 75 | def wordbreak2(s, words): 76 | words = set(words) 77 | for combo in wordbreak2_generator(s, words): 78 | print combo 79 | 80 | 81 | ''' 82 | What if we allow unmatched characters, but they should be as few as possible. 83 | Capitalize unmatched string. 84 | For example, given 85 | s = "ithinktomlikescatsanddog", 86 | dict = ["think", "like", "likes", "cat", "cats", "and", "sand", "dog"]. 87 | A solution is ["I think TOM likes cats and dog", "I think TOM likes cat sand dog"]. 88 | ''' 89 | def wordbreak3_match(s, words): 90 | global MAX_UNMATCHED 91 | if s == '': 92 | yield 0, '' 93 | else: 94 | for u in range(MAX_UNMATCHED+1): 95 | sub = s[u:] 96 | for i in range(1, len(sub)+1): 97 | first = sub[:i] 98 | if first not in words: continue 99 | for unmatched, split in wordbreak3_match(sub[i:], words): 100 | yield unmatched+u, s[:u].upper() + ' '+ first + ' ' + split 101 | 102 | MAX_UNMATCHED = 0 103 | def wordbreak3(s, words): 104 | global MAX_UNMATCHED 105 | MAX_UNMATCHED = len(s) 106 | 107 | min_unmatched = len(s) 108 | best_split = [] 109 | for u, split in wordbreak3_match(s, words): 110 | if u < min_unmatched: 111 | min_unmatched = u 112 | best_split = split 113 | print best_split 114 | return best_split 115 | 116 | 117 | 118 | if __name__ == '__main__': 119 | ''' 120 | s = "catsanddogseat" 121 | words = set(["cat", "cats", "and", "sand", "dog", "dogs", "eat", "seat"]) 122 | print wordbreak(s, words) 123 | print wordbreak_DP(s, words) 124 | print wordbreak_memo(s, words) 125 | wordbreak2(s, words) 126 | ''' 127 | 128 | s = "ithinktomlikescatsanddog" 129 | dict = ["think", "like", "likes", "cat", "cats", "and", "sand", "dog"] 130 | wordbreak3(s, dict) 131 | 132 | 133 | -------------------------------------------------------------------------------- /reverse_sth.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Reverse Integer 4 | Leetcode: Reverse Linked List II 5 | Leetcode: Rotate List 6 | Leetcode: Reverse Nodes in k-Group 7 | ''' 8 | from __future__ import division 9 | import random 10 | from LinkedList import Node 11 | 12 | ''' 13 | Reverse digits of an integer. 14 | Example1: x = 123, return 321 15 | Example2: x = -123, return -321 16 | ''' 17 | # consider 0 18 | # consider the last few digits == 0 19 | def reverse_int(x): 20 | x = str(x)[::-1] 21 | # remove the first zero 22 | for i,ch in enumerate(x): 23 | if ch != '0': break 24 | x = x[i:] 25 | if x[-1] == '-': x = '-' + x[:-1] 26 | return x 27 | 28 | 29 | ''' 30 | Leetcode: Reverse Linked List II 31 | Reverse a linked list from position m to n. Do it in-place and in one-pass. 32 | For example: 33 | Given 1->2->3->4->5->NULL, m = 2 and n = 4, 34 | return 1->4->3->2->5->NULL. 35 | Note: Given m, n satisfy the following condition: 1 <= m <= n <= length of list. 36 | ''' 37 | # three pointers: 38 | # (1) prevM, the one before m-th element 39 | # (2) head, scanning through the list; act when pointing to (m+1)-th ~ n-th elements 40 | # (3) prev, previous node of head 41 | def reverse_llist(head, m, n): 42 | if m >= n: return head 43 | dummy = Node(0, next=head) 44 | prev = prevM = dummy 45 | for i in range(1,n+1): 46 | if i == m: 47 | # prevM.next = the first element to revert (m-th) 48 | prevM = prev 49 | elif m < i <= n: 50 | # insert head after prevM 51 | prev.next = head.next 52 | head.next = prevM.next 53 | preM.next = head 54 | head = prev # points to the later element 55 | prev = head 56 | head = head.next 57 | return dummy.next 58 | 59 | 60 | ''' 61 | Given a list, rotate the list to the right by k places, where k is non-negative. 62 | For example: 63 | Given 1->2->3->4->5->NULL and k = 2, 64 | return 4->5->1->2->3->NULL. 65 | ''' 66 | def rotate_llist(head, k): 67 | dummy = Node(-1, next=head) 68 | # count how many nodes in the list 69 | len = 1 70 | last = head # find the last node 71 | while last.next: 72 | len += 1 73 | last = last.next 74 | k = k % len 75 | if k == 0: return dummy.next 76 | 77 | # reset 78 | prev = dummy 79 | head = dummy.next 80 | # point to the new head and the previous node 81 | for _ in range(len-k): 82 | prev = head 83 | head = prev.next 84 | prev.next = last.next 85 | last.next = dummy.next 86 | dummy.next = head 87 | return dummy.next 88 | 89 | 90 | ''' 91 | Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is. 92 | 93 | You may not alter the values in the nodes, only nodes itself may be changed. 94 | Only constant memory is allowed. 95 | 96 | For example, 97 | Given this linked list: 1->2->3->4->5 98 | For k = 2, you should return: 2->1->4->3->5 99 | For k = 3, you should return: 3->2->1->4->5 100 | ''' 101 | # ~O(1) in space 102 | def reverse_nodes(head, k): 103 | if k <= 1: return head 104 | dummy = Node(-1, next=head) 105 | # count the number of nodes 106 | len = 0 107 | while head: 108 | len += 1 109 | head = head.next 110 | # point to the previous node of the first node in the reverse section of length k. 111 | starter = dummy 112 | for _ in range(len//k): 113 | prev = starter 114 | head = starter.next 115 | # this part is similar to "Reverse Linked List II" 116 | for _ in range(k-1): # insert k-1 times 117 | if head is None: 118 | return dummy.next 119 | prev = head 120 | head = head.next 121 | # inset head to be right after starter 122 | prev.next = head.next 123 | head.next = starter.next 124 | starter.next = head 125 | head = prev 126 | 127 | # set up new starter 128 | starter = prev 129 | return dummy.next 130 | 131 | 132 | if __name__ == '__main__': 133 | #print reverse_int(123099999) 134 | #print reverse_int(-19900000) 135 | 136 | l1 = Node(1, Node(1, Node(2))) 137 | l2 = Node(2, Node(3, Node(3, Node(5, Node(5, Node(7)))))) 138 | print reverse_nodes(Node(1, Node(2, Node(3, Node(4, Node(5, Node(6)))))), 2) 139 | print reverse_nodes(Node(1, Node(2, Node(3, Node(4, Node(5, Node(6)))))), 3) 140 | print reverse_nodes(Node(1, Node(2, Node(3, Node(4, Node(5, Node(6)))))), 4) 141 | 142 | 143 | -------------------------------------------------------------------------------- /gas_station.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Gas Station 4 | 5 | There are N gas stations along a circular route, where the amount of gas at station i is gas[i]. 6 | You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations. 7 | Return the starting gas station's index if you can travel around the circuit once, otherwise return -1. 8 | 9 | Note: The solution is guaranteed to be unique. 10 | ''' 11 | from __future__ import division 12 | import random 13 | 14 | 15 | # We can use a Queue to store the current tour. We first enqueue first petrol pump to the queue, we keep enqueueing petrol pumps till we either complete the tour, or current amount of petrol becomes negative. If the amount becomes negative, then we keep dequeueing petrol pumps till the current amount becomes positive or queue becomes empty. 16 | def gas_station(gas, cost): 17 | n = len(gas) 18 | start = 0; next = 1 19 | Q = [] 20 | cur_gas = gas[start] - cost[start] 21 | while start != next or cur_gas < 0: 22 | while start != next and cur_gas < 0: 23 | # pop, changing starting point 24 | cur_gas -= gas[start] - cost[start] 25 | start = (start+1)%n 26 | if start == 0: # go back to the first trial 27 | return -1 28 | cur_gas += gas[next] - cost[next] 29 | next = (next+1)%n 30 | return start 31 | 32 | 33 | ''' 34 | What if we want to keep the leftover gas as much as possible? 35 | ''' 36 | # G(i,j) = the maximum leftover gas a car goes from i-th station to j-th. 37 | # the car can use gas at i-th but not at j-th 38 | # only valid when G(i,j) >= 0 39 | # G(i,j) = max{G(i,mid)+G(k,mid) for i < mid < j, 40 | # gas[i] - (cost[i]+...+cost[j])} 41 | # We use G(i,i) for a circular route. 42 | # ~ O(n^3) 43 | def gas_station2(gas, cost): 44 | n = len(gas) 45 | G = {} 46 | for i in range(n): G[i,(i+1)%n] = gas[i] - cost[i] 47 | print G 48 | 49 | for k in range(2,n+1): 50 | for i in range(n): 51 | j = (i+k) % n 52 | G[i,j] = -float('inf') 53 | sum_cost = cost[i] 54 | # with stop 55 | for mid in range(i+1,i+k): 56 | mid = mid % n 57 | if G[i,mid] >= 0: 58 | G[i,j] = max(G[i,j], G[i,mid]+G[mid,j]) 59 | sum_cost += cost[mid] 60 | # no stop 61 | if gas[i]-sum_cost > 0: 62 | G[i,j] = max(G[i,j], gas[i]-sum_cost) 63 | 64 | circles = dict((i, G[i,j]) for i,j in G if j == i) 65 | print circles 66 | return max(circles.values()) >= 0 67 | 68 | 69 | ''' 70 | What if we want to get the trip with the minimum times of stops? 71 | ''' 72 | # G(i,j,s) = maximum leftover gas from i-th to j-th station with s stops in-between; 0 <= s <= j-i-1 73 | # G(i,j,0) = gas[i] - sum(cost[i..j-1]) 74 | # G(i,j,s) = max{G(i,mid,s1) + G(mid,j,s2) for 75 | # 0 <= s1 <= mid-i-1, 76 | # 0 <= s2 <= j-mid-1, 77 | # s1+s2+1 == s} 78 | # Final results: argmin_s G(i,j,s) >= 0. 79 | # ~O(n^4) 80 | def gas_station3(gas, cost): 81 | n = len(gas) 82 | G = {} 83 | for i in range(n): G[i,(i+1)%n,0] = gas[i] - cost[i] 84 | 85 | for k in range(2, n+1): 86 | for i in range(n): 87 | j = i+k 88 | G[i,j%n,0] = gas[i] - sum([cost[x%n] for x in range(i,j)]) 89 | for s in range(1, k): 90 | G[i,j%n,s] = -float('inf') 91 | for mid in range(i+1,i+k): 92 | for s1 in range(0, mid-i): 93 | s2 = s-s1-1 94 | if s2 < 0 or s2 > j-mid-1: continue 95 | 96 | print '(i,j,s)=(%d,%d,%d)'%(i,j,s), s1, s2 97 | G[i,j%n,s] = max(G[i,j%n,s], \ 98 | G[i,mid%n,s1]+G[mid%n,j%n,s2]) 99 | #''' 100 | for x,y,z in G: 101 | if z == s: 102 | print x,y,z, ':', G[x,y,z] 103 | #''' 104 | 105 | for k,v in G.items(): print k,v 106 | 107 | min_step = n-1 108 | for i in range(n): 109 | args = [x for x in range(0,n) if G[i,i,x] > 0] 110 | if args: 111 | min_s = min(args) 112 | min_step = min(min_step, min_s) 113 | print i,'-->',i, 'steps:',min_s, 'leftover gas:', G[i,i,min_s] 114 | return min_step 115 | 116 | 117 | # Greedy algorithm, starting at 118 | 119 | 120 | if __name__ == '__main__': 121 | gas = [10,5,10,5,10] 122 | cost = [2,2,2,5,2] 123 | print gas_station3(gas, cost) 124 | 125 | 126 | -------------------------------------------------------------------------------- /longest_palin_substr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Leetcode: Longest Palindromic Substring 4 | 5 | Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 6 | 7 | http://leetcode.com/2011/11/longest-palindromic-substring-part-i.html 8 | http://leetcode.com/2011/11/longest-palindromic-substring-part-ii.html 9 | ''' 10 | from __future__ import division 11 | 12 | # Using pair of indices for same lements 13 | # ~O(n^2) 14 | def longest_palin_substr1(s): 15 | print s, '-->', 16 | elems = set(list(s)) 17 | pos = {} 18 | for i, elem in enumerate(list(s)): 19 | pos.setdefault(elem,[]).append(i) 20 | #print pos 21 | # Get pairs of locations with same element 22 | pairs = set() 23 | for elem in pos: 24 | elem_pos = pos[elem] 25 | for i in range(len(elem_pos)): 26 | for j in range(i+1, len(elem_pos)): 27 | pairs.add((elem_pos[i],elem_pos[j])) 28 | # Prioritize distant pairs 29 | sorted_pairs = sorted(pairs, 30 | key=lambda x:x[1]-x[0], 31 | reverse=True) 32 | #print sorted_pairs 33 | for start, end in sorted_pairs: 34 | i, j = start, end 35 | while i < j: 36 | if not (i,j) in pairs: break 37 | i += 1 38 | j -= 1 39 | if i >= j: 40 | # find a match! 41 | return s[start:end+1] 42 | return '' 43 | 44 | 45 | # Reverse S and become S'. Find the longest common substring between S and S', which must also be the longest palindromic substring. 46 | # For example, S="abacdfgdcaba", S'="abacdgfdcaba". 47 | # The longest common substring between S and S' is "abacd". Clearly, this is not a valid palindrome. 48 | def longest_palin_substr2(s): 49 | n = len(s) 50 | if n == 0: return '' 51 | rev_s = s[::-1] 52 | # longest common string with same indices (i <--> n-1-i) 53 | # DP? 54 | longest_common_string(s, rev_s) 55 | 56 | 57 | # DP: P(i,j) = true if S[i:j+1] is palindrome 58 | # P(i,j) = P(i+1,j-1) and S[i] == S[j] 59 | # ~O(n^2) in time, ~O(n^2) in space 60 | def longest_palin_substr3(s): 61 | n = len(s) 62 | if n == 0: return '' 63 | P = {} 64 | for i in range(n): P[(i,i)] = True 65 | # k = j-i between 0 and n-1 66 | for k in range(n-1): 67 | for i in range(n): 68 | j = i+k 69 | if j >= n: continue 70 | if i+1 <= j-1: 71 | P[(i,j)] = P[(i+1,j-1)] and s[i] == s[j] 72 | else: 73 | P[(i,j)] = s[i] == s[j] 74 | start, end = max([k for k in P if P[k]], 75 | key=lambda x:x[1]-x[0]) 76 | return s[start:end+1] 77 | 78 | 79 | # Find center of a substring palindrome and expand it 80 | # ~O(n^2) in time and ~O(1) in space 81 | def longest_palin_substr4(s): 82 | n = len(s) 83 | if n == 0: return '' 84 | max_pali = '' 85 | # Center can be on a letter or between letters 86 | for i in range(n): 87 | for j in [i,i+1]: 88 | # Center at s[i:j+1] 89 | while i >= 0 and j <= n-1: 90 | if s[i] != s[j]: break 91 | i -= 1 92 | j += 1 93 | cur_pali = s[i+1:j] 94 | if len(cur_pali) > len(max_pali): 95 | max_pali = cur_pali 96 | return max_pali 97 | 98 | 99 | # Manacher's Algorithm 100 | # http://leetcode.com/2011/11/longest-palindromic-substring-part-ii.html 101 | # http://www.felix021.com/blog/read.php?2040 102 | # ~O(n) 103 | def longest_palin_substr5(s): 104 | # reformat the string 105 | s = list(s) 106 | # so that all the palindrome substrings are of odd length 107 | for i in range(len(s)+1): s.insert(i*2,'#') 108 | print s 109 | p = defaultdict(int) # left/right length of palindrome centered at s[i] 110 | max_center = 0 # current maximum palindrom's center 111 | max_upper = 0 # maximum palindrom's upper boundary, max_center+P[max_center] 112 | for i in range(1,len(s)): 113 | # i & j are symmetric points to max_center_id 114 | j = 2*max_center - i 115 | p[i] = min(p[j], max_upper-i) if max_upper > i else 1 116 | while i-p[i] >= 0 and i+p[i] <= len(s)-1 and s[i+p[i]] == s[i-p[i]]: 117 | p[i]+=1 118 | if p[i]+i > max_upper: 119 | max_upper = p[i]+i 120 | max_center = i 121 | print 's:', ','.join(s) 122 | print 'p:', ','.join(map(str, [p[i] for i in range(len(s))])) 123 | return max(p.values())-1 124 | 125 | 126 | # Using suffix tree 127 | # ~O(nlogn) 128 | 129 | 130 | if __name__ == '__main__': 131 | __func__ = longest_palin_substr4 132 | print __func__('cabcbaabac') 133 | print __func__('abbaaa') 134 | print __func__('abacdfgdcaba') 135 | print __func__('aaaaaaa') 136 | print __func__('') 137 | 138 | 139 | -------------------------------------------------------------------------------- /best_time_buy_sell.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import division 4 | import random 5 | 6 | 7 | ''' 8 | Leetcode: Best Time to Buy and Sell Stock 9 | Say you have an array for which the ith element is the price of a given stock on day i. 10 | If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit. 11 | ''' 12 | # Find i, j to maximize A[j]-A[i] and i < j 13 | # O(nlogn) 14 | def stock1(A): 15 | n = len(A) 16 | sorted_days = sorted(range(n), key=lambda x:A[x]) 17 | i,j = 0,n-1 18 | while sorted_days[i] > sorted_days[j]: 19 | i += 1; j -= 1 20 | buy = sorted_days[i] 21 | sell = sorted_days[j] 22 | print 'Buy on day', buy, A[buy] 23 | print 'Sell on day', sell, A[sell] 24 | return sorted_days[i], sorted_days[j] 25 | 26 | # Scan through each day and consider it as a "sell" day, we know 27 | # which day is the corresponding best "buy" day! ~O(n) 28 | def stock1_better(A): 29 | min_day = buy = sell = 0 # day indices 30 | max_diff = 0 31 | for i in range(len(A)): 32 | if A[i] < A[min_day]: min_day = i 33 | cur_diff = A[i] - A[min_day] # always sell after buy! 34 | if cur_diff > max_diff: 35 | buy = min_day 36 | sell = i 37 | max_diff = cur_diff 38 | print 'Buy on day', buy, ':', A[buy] 39 | print 'Sell on day', sell, ':', A[sell] 40 | return sell, buy 41 | 42 | 43 | ''' 44 | Leetcode: Best Time to Buy and Sell Stock II 45 | Say you have an array for which the ith element is the price of a given stock on day i. 46 | Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again). 47 | ''' 48 | # Consider: (a,b,c,d) and c < b 49 | # X = d-a; Y = (b-a) + (d-c) then X < Y 50 | # Compute the difference between each two consecutive days, select positive values 51 | def stock2(A): 52 | transactions = [] 53 | profit = 0 54 | buy = sell = 0 55 | for i in range(1,len(A)): 56 | if A[i] - A[i-1] > 0: 57 | sell = i 58 | else: 59 | # finish previous transaction 60 | if sell > buy and A[sell] - A[buy] > 0: 61 | transactions.append((buy, sell)) 62 | profit += A[sell] - A[buy] 63 | # start a new transaction 64 | buy = sell = i 65 | # last transaction 66 | if sell > buy and A[sell] - A[buy] > 0: 67 | transactions.append((buy, sell)) 68 | profit += A[sell] - A[buy] 69 | print 'Profit:', profit 70 | return transactions 71 | 72 | 73 | ''' 74 | Leetcode: Best Time to Buy and Sell Stock III 75 | Say you have an array for which the ith element is the price of a given stock on day i. Design an algorithm to find the maximum profit. You may complete at most two transactions. You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again). 76 | ''' 77 | # Find i1, j1, i2, j2 to maximize A[j2]-A[i2]+A[j1]-A[i1] and i1 < j1 <= i2 < j2 78 | # We are actually trying to break the day at each time instance, by adding the potential max profit before and after it together. By recording history and future for each time point, we can again do this within O(n) time. 79 | def stock3(A): 80 | max_profit = 0 81 | max_split = None 82 | # max profit you can get before day i 83 | max_history_profit = {0:(0, (0,0))} 84 | min_day = 0 85 | for i in range(1,len(A)): 86 | if A[i] <= A[min_day]: min_day = i 87 | cur_diff = A[i]-A[min_day] 88 | if max_history_profit[i-1][0] > cur_diff: 89 | max_history_profit[i] = max_history_profit[i-1] 90 | else: 91 | max_history_profit[i] = (cur_diff, (min_day,i)) 92 | 93 | # max profit you can get after day i 94 | max_future_profit = {len(A)-1:(0, (len(A)-1,len(A)-1))} 95 | max_day = len(A)-1 96 | for i in reversed(range(len(A)-1)): 97 | if A[i] > A[max_day]: max_day = i 98 | cur_diff = A[max_day] - A[i] 99 | if max_future_profit[i+1][0] > cur_diff: 100 | max_future_profit[i] = max_future_profit[i+1] 101 | else: 102 | max_future_profit[i] = (cur_diff, (i,max_day)) 103 | if max_history_profit[i][0] + max_future_profit[i][0] > max_profit: 104 | max_profit = max_history_profit[i][0] + max_future_profit[i][0] 105 | max_split = i 106 | print 'split:', max_split, 107 | print max_history_profit[max_split][1], max_future_profit[max_split][1] 108 | print 'profit:', max_profit 109 | return max_profit 110 | 111 | 112 | if __name__ == '__main__': 113 | A = [8,9,12,11,13,12,15] 114 | print A, stock3(A) 115 | A = [10,5,5,5,5,6,11,9,13,8,10,11,12] 116 | print A, stock3(A) 117 | 118 | --------------------------------------------------------------------------------