├── .gitignore ├── Anagrams.py ├── Backpack II.py ├── Backpack.py ├── Binary Representation.py ├── Binary Search.py ├── Building Outline.py ├── Coins in a Line II.py ├── Coins in a Line III.py ├── Coins in a Line.py ├── Compare Strings.py ├── Container With Most Water.py ├── Continuous Subarray Sum II.py ├── Continuous Subarray Sum.py ├── Convert Expression to Polish Notation.py ├── Convert Expression to Reverse Polish Notation.py ├── Convert Integer A to Integer B.py ├── Copy Books.py ├── Count of Smaller Number before itself.py ├── Count of Smaller Number.py ├── Delete Digits.py ├── Divide Two Integers.py ├── Evaluate Reverse Polish Notation.py ├── Expression Evaluation.py ├── Expression Tree Build.py ├── Fibonacci.py ├── Find Peak Element II.py ├── Find Peak Element.py ├── Find the Connected Component in the Undirected Graph.py ├── Find the Missing Number.py ├── Find the Weak Connected Component in the Directed Graph.py ├── First Bad Version.py ├── First Missing Positive.py ├── Hash Function.py ├── Heapify.py ├── Implement Iterator of Binary Search Tree.py ├── Implement Queue by Stacks.py ├── Insert Node in a Binary Search Tree.py ├── Interleaving Positive and Negative Numbers.py ├── Interval Minimum Number.py ├── Interval Sum II.py ├── Interval Sum.py ├── Kth Largest Element.py ├── Kth Prime Number.py ├── LICENSE ├── LRU Cache.py ├── Largest Number.py ├── Longest Common Subsequence.py ├── Longest Common Substring.py ├── Longest Increasing Continuous subsequence.py ├── Longest Increasing Subsequence.py ├── Longest Palindromic Substring.py ├── Longest Substring Without Repeating Characters.py ├── Longest Substring with At Most K Distinct Characters.py ├── Longest Words.py ├── Lowest Common Ancestor.py ├── Majority Number II.py ├── Majority Number III.py ├── Majority Number.py ├── Matrix Zigzag Traversal.py ├── Max Tree.py ├── Maximal Square.py ├── Maximum Gap.py ├── Maximum Product Subarray.py ├── Maximum Subarray Difference.py ├── Maximum Subarray II.py ├── Maximum Subarray III.py ├── Median II.py ├── Median.py ├── Minimum Adjustment Cost.py ├── Minimum Subarray.py ├── Number of Airplanes in the Sky.py ├── Number of Islands II.py ├── Number of Islands.py ├── Nuts & Bolts Problem.py ├── Palindrome Partitioning.py ├── Permutation Index II.py ├── Permutation Index.py ├── Permutation Sequence.py ├── Post Office Problem.py ├── Previous Permuation.py ├── Print Numbers by Recursion.py ├── Product of Array Exclude Itself.py ├── README.md ├── Rehashing.py ├── Remove Node in Binary Search Tree.py ├── Rotate List.py ├── Route Between Two Nodes in Graph.py ├── Search Range in Binary Search Tree.py ├── Segment Tree Build.py ├── Segment Tree Modify.py ├── Segment Tree Query II.py ├── Segment Tree Query.py ├── Single Number III.py ├── Singleton.py ├── Sliding Window Maximum.py ├── Sliding Window Median.py ├── Sort Letters by Case.py ├── Space Replacement.py ├── Subarray Sum II.py ├── Subarray Sum.py ├── Submatrix Sum.py ├── The Smallest Difference.py ├── Topological Sorting.py ├── Trapping Rain Water II.py ├── Triangle Count.py ├── Unique Binary Search Trees II.py ├── Unique Binary Search Trees.py ├── Update Bits.py ├── Wood Cut.py ├── Word Search II.py ├── archive ├── Count of Smaller Number before itself.py ├── Sliding Window Median TLE.py ├── Sliding Window Median error.py └── __init__.py ├── java ├── pom.xml └── src │ └── main │ └── java │ ├── BuildingOutline │ └── Solution.java │ ├── ContinuousSubarraySumII │ └── Solution.java │ ├── CountofSmallerNumberbeforeitself │ └── Solution.java │ └── FourSum │ └── Solution.java ├── k Sum II.py └── k Sum.py /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | # External tool builders 19 | .externalToolBuilders/ 20 | 21 | # Locally stored "Eclipse launch configurations" 22 | *.launch 23 | 24 | # CDT-specific 25 | .cproject 26 | 27 | # PDT-specific 28 | .buildpath 29 | Debug/ 30 | Release/ 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | log/ 217 | data/ 218 | # python byte code 219 | *.pyc 220 | 221 | ############# 222 | ## Sublime 223 | ############# 224 | # Ignore production server environment files 225 | uwsgi_params 226 | # sublime text 227 | *.sublime-workspace 228 | 229 | 230 | ############# 231 | ## Idea 232 | ############# 233 | .idea 234 | .idea/ 235 | *.eml 236 | *.iml 237 | 238 | ## I/O 239 | *.in 240 | *.out 241 | pdf/ -------------------------------------------------------------------------------- /Anagrams.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of strings, return all groups of strings that are anagrams. 3 | 4 | Example 5 | Given ["lint", "intl", "inlt", "code"], return ["lint", "inlt", "intl"]. 6 | 7 | Given ["ab", "ba", "cd", "dc", "e"], return ["ab", "ba", "cd", "dc"]. 8 | 9 | Note 10 | All inputs will be in lower-case 11 | """ 12 | from collections import defaultdict 13 | __author__ = 'Daniel' 14 | 15 | 16 | class Solution(object): 17 | def anagrams(self, strs): 18 | ret = [] 19 | cnt = defaultdict(int) 20 | for s in strs: 21 | enc = self.encode(s) 22 | cnt[enc] += 1 23 | 24 | for s in strs: 25 | enc = self.encode(s) 26 | if cnt[enc] > 1: 27 | ret.append(s) 28 | 29 | return ret 30 | 31 | def encode(self, s): 32 | ret = [0 for _ in xrange(26)] 33 | for c in s: 34 | ret[ord(c)-ord('a')] += 1 35 | 36 | return "".join(map(str, ret)) -------------------------------------------------------------------------------- /Backpack II.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given n items with size A[i] and value V[i], and a backpack with size m. What's the maximum value can you put into the 3 | backpack? 4 | """ 5 | __author__ = 'Danyang' 6 | 7 | 8 | class Solution: 9 | def backPackII(self, m, A, V): 10 | """ 11 | Left f_{i, c} represents the maximum value the bag has at the index i for a bag with capacity c. 12 | 13 | dp: 14 | f[i][c]=max{f[i-1][c], # not choose the i-th item 15 | f[i-1][c-w[i]] + v[i] # choose the i-th item 16 | } 17 | 18 | optimized the data structure to 19 | f[v]=max{f[v],f[v-c[i]]+w[i]} 20 | 21 | NEED TO KEEP A COPY OF (i-1) STATE. 22 | 23 | :param m: An integer m denotes the size of a backpack 24 | :param A & V: Given n items with size A[i] and value V[i] 25 | :return: The maximum size 26 | """ 27 | n = len(A) 28 | f = [0 for _ in xrange(m+1)] # plus 1 for dummy 29 | for i in xrange(1, n+1): 30 | copy = list(f) 31 | for j in xrange(1, m+1): 32 | # decide whether to put A[i-1] 33 | if j-A[i-1]>=0: 34 | f[j] = max(copy[j], copy[j-A[i-1]]+V[i-1]) 35 | else: 36 | f[j] = copy[j] 37 | return f[m] -------------------------------------------------------------------------------- /Backpack.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given n items with size A[i], an integer m denotes the size of a backpack. How full you can fill this backpack? 3 | """ 4 | __author__ = 'Danyang' 5 | 6 | 7 | class Solution(object): 8 | def backPack(self, m, A): 9 | """ 10 | Left f_{i, c} represents the maximum value the bag has at the index i for a bag with capacity c. 11 | 12 | dp: 13 | f[i][c]=max{f[i-1][c], # not choose the i-th item 14 | f[i-1][c-w[i]] + v[i] # choose the i-th item 15 | } 16 | 17 | optimized the data structure to 18 | f[v]=max{f[v],f[v-c[i]]+w[i]} 19 | 20 | NEED TO KEEP A COPY OF (i-1) STATE. 21 | 22 | :param m: An integer m denotes the size of a backpack 23 | :param A: Given n items with size A[i] 24 | :return: The maximum size 25 | """ 26 | n = len(A) 27 | f = [0 for _ in xrange(m+1)] # plus 1 for dummy 28 | for i in xrange(1, n+1): 29 | copy = list(f) 30 | for j in xrange(1, m+1): 31 | # decide whether to put A[i-1] 32 | if j-A[i-1] >= 0: 33 | f[j] = max(copy[j], copy[j-A[i-1]]+A[i-1]) 34 | else: 35 | f[j] = copy[j] 36 | return f[m] 37 | 38 | 39 | class Solution_TLE(object): 40 | def backPack(self, m, A): 41 | """ 42 | search, brute force 43 | :param m: An integer m denotes the size of a backpack 44 | :param A: Given n items with size A[i] 45 | :return: The maximum size 46 | """ 47 | result = [0] 48 | self.dfs(A, 0, m, result) 49 | return result[0] 50 | 51 | def dfs(self, seq, cur, m, result): 52 | if cur > m: 53 | return 54 | 55 | result[0] = max(result[0], cur) 56 | if seq: 57 | self.dfs(seq[1:], cur+seq[0], m, result) 58 | self.dfs(seq[1:], cur, m, result) 59 | 60 | 61 | class Solution_MLE(object): 62 | def backPack(self, m, A): 63 | """ 64 | dp 65 | f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]} 66 | 67 | :param m: An integer m denotes the size of a backpack 68 | :param A: Given n items with size A[i] 69 | :return: The maximum size 70 | """ 71 | n = len(A) 72 | f = [[0 for _ in xrange(m+1)] for _ in xrange(n+1)] # plus 1 for dummy 73 | for i in xrange(1, n+1): 74 | for j in xrange(1, m+1): 75 | # decide whether to put A[i-1] 76 | if j-A[i-1] >= 0: 77 | f[i][j] = max(f[i-1][j], f[i-1][j-A[i-1]]+A[i-1]) 78 | else: 79 | f[i][j] = f[i-1][j] 80 | return f[n][m] 81 | 82 | 83 | if __name__ == "__main__": 84 | print Solution().backPack(11, [2, 3, 5, 7]) -------------------------------------------------------------------------------- /Binary Representation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a (decimal - e.g. 3.72) number that is passed in as a string, return the binary representation that is passed in 3 | as a string. If the number can not be represented accurately in binary, return ERROR 4 | 5 | Example 6 | For n=3.72, return ERROR 7 | 8 | For n=3.5, return 11.1 9 | """ 10 | from decimal import * 11 | 12 | __author__ = 'Danyang' 13 | 14 | 15 | class Solution: 16 | def binaryRepresentation(self, n): 17 | """ 18 | NOTICE: As of 14 April 2015, LintCode OJ has bug in test case 12 of this question since 0.6418459415435791 19 | cannot be represented as binary representation because 0.6418459415435791 becomes 20 | 0.10100100010100000000001111111111111111111111111111111111111000... 21 | 22 | 23 | difficult part: determine whether the fraction can be represented in binary 24 | if cannot represent, repeat forever, then cut-off at 32bit as in int 25 | 26 | One may check whether the last digit of decimal part is 5, but it does not work for 0.12345 27 | 28 | :param n: Given a decimal number that is passed in as a string 29 | :return: A string 30 | """ 31 | dec_part = "" 32 | if "." in n: 33 | int_part, dec_part = n.split(".") 34 | getcontext().prec = len(dec_part)+1 35 | dec_part = "."+dec_part 36 | if not self.is_representable(Decimal(dec_part)): 37 | return "ERROR" 38 | else: 39 | int_part = n 40 | 41 | a = self.natural_num_to_bin(int(int_part)) 42 | b = self.fraction_to_bin(Decimal(dec_part)) 43 | 44 | if a == "": 45 | a = "0" 46 | if b == "": 47 | return a 48 | else: 49 | return a+"."+b 50 | 51 | @staticmethod 52 | def natural_num_to_bin(n): 53 | """ 54 | 55 | :type n: int 56 | :param n: 57 | :return: string representation 58 | """ 59 | sb = [] # string buffer 60 | while n > 0: 61 | sb.append(n&1) 62 | n >>= 1 63 | 64 | return "".join(map(str, reversed(sb))) 65 | 66 | @staticmethod 67 | def fraction_to_bin(n): 68 | """ 69 | To convert fractional part of binary representation: x2 can take the whole part. 70 | :type n: Decimal 71 | :param n: 72 | :return: string representation 73 | """ 74 | sb = [] 75 | while n > 0: 76 | if len(sb) > 32: 77 | return "ERROR" 78 | n *= Decimal(2) 79 | cur = int(n) 80 | sb.append(cur) 81 | n -= Decimal(cur) 82 | return "".join(map(str, sb)) 83 | 84 | @staticmethod 85 | def is_representable(frac): 86 | """ 87 | to test whether the fraction part is representable in binary 88 | 89 | :type frac: Decimal 90 | :param frac: 91 | :return: 92 | """ 93 | while True: 94 | temp = str(frac).rstrip("0") 95 | if temp.endswith("."): 96 | return True 97 | if not temp.endswith("5"): 98 | return False 99 | frac *= Decimal(2) 100 | 101 | 102 | if __name__ == "__main__": 103 | assert Solution().binaryRepresentation("0.72") == "ERROR" 104 | assert Solution().binaryRepresentation("0.125") == "0.001" 105 | assert Solution().binaryRepresentation("0.6418459415435791") == "ERROR" 106 | -------------------------------------------------------------------------------- /Binary Search.py: -------------------------------------------------------------------------------- 1 | """ 2 | Binary search is a famous question in algorithm. 3 | 4 | For a given sorted array (ascending order) and a target number, find the first index of this number in O(log n) time 5 | complexity. 6 | 7 | If the target number does not exist in the array, return -1. 8 | """ 9 | __author__ = 'Danyang' 10 | 11 | 12 | class Solution: 13 | def binarySearch(self, nums, target): 14 | """ 15 | basics 16 | 17 | :param nums: The integer array 18 | :param target: Target number to find 19 | :return the first position of target in nums, position start from 0 20 | """ 21 | l = 0 22 | h = len(nums) 23 | while l < h: 24 | mid = (l+h)/2 25 | if nums[mid] == target: 26 | while mid >= 0 and nums[mid-1] == nums[mid]: mid -= 1 27 | return mid 28 | elif nums[mid] < target: 29 | l = mid+1 30 | else: 31 | h = mid 32 | return -1 33 | 34 | -------------------------------------------------------------------------------- /Building Outline.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given N buildings in a x-axis, each building is a rectangle and can be represented by a triple (start, end, height), 3 | where start is the start position on x-axis, end is the end position on x-axis and height is the height of the building. 4 | Buildings may overlap if you see them from far away, find the outline of them. 5 | 6 | An outline can be represented by a triple, (start, end, height), where start is the start position on x-axis of the 7 | outline, end is the end position on x-axis and height is the height of the outline. 8 | 9 | Building Outline 10 | 11 | Example 12 | Given 3 buildings: 13 | 14 | [ 15 | [1, 3, 3], 16 | [2, 4, 4], 17 | [5, 6, 1] 18 | ] 19 | The outlines are: 20 | 21 | [ 22 | [1, 2, 3], 23 | [2, 4, 4], 24 | [5, 6, 1] 25 | ] 26 | Note 27 | Please merge the adjacent outlines if they have the same height and make sure different outlines cant overlap on x-axis. 28 | """ 29 | __author__ = 'Daniel' 30 | import heapq 31 | from collections import defaultdict 32 | 33 | 34 | class Building(object): 35 | def __init__(self, h): 36 | self.h = h 37 | self.deleted = False 38 | 39 | def __cmp__(self, other): 40 | # max-heap 41 | return other.h - self.h 42 | 43 | 44 | class Event(object): 45 | def __init__(self): 46 | """ 47 | Event at certain x-coordinate 48 | Event for the building starting and the building ending 49 | """ 50 | self.starts = [] 51 | self.ends = [] 52 | 53 | 54 | class Solution: 55 | def buildingOutline(self, buildings): 56 | """ 57 | MLE 58 | 59 | :param buildings: A list of lists of integers 60 | :return: A list of lists of integers 61 | """ 62 | events = defaultdict(Event) 63 | for start, end, height in buildings: 64 | building = Building(height) 65 | events[start].starts.append(building) 66 | events[end].ends.append(building) 67 | 68 | ret = [] 69 | cur_heap = [] 70 | cur_max_hi = 0 71 | begin = None 72 | for x, event in sorted(events.items()): 73 | for building in event.starts: # beginning 74 | heapq.heappush(cur_heap, building) 75 | for building in event.ends: # finishing 76 | building.deleted = True 77 | 78 | while cur_heap and cur_heap[0].deleted: 79 | heapq.heappop(cur_heap) 80 | 81 | new_hi = cur_heap[0].h if cur_heap else 0 82 | if cur_max_hi != new_hi: 83 | if cur_max_hi != 0: 84 | ret.append([begin, x, cur_max_hi]) 85 | begin = x 86 | 87 | cur_max_hi = new_hi 88 | 89 | return ret 90 | 91 | if __name__ == "__main__": 92 | assert Solution().buildingOutline([ 93 | [1, 3, 3], 94 | [2, 4, 4], 95 | [5, 6, 1] 96 | ]) == [[1, 2, 3], [2, 4, 4], [5, 6, 1]] -------------------------------------------------------------------------------- /Coins in a Line II.py: -------------------------------------------------------------------------------- 1 | """ 2 | There are n coins with different value in a line. Two players take turns to take one or two coins from left side until 3 | there are no more coins left. The player who take the coins with the most value wins. 4 | 5 | Could you please decide the first player will win or lose? 6 | 7 | Example 8 | Given values array A = [1,2,2], return true. 9 | 10 | Given A = [1,2,4], return false. 11 | 12 | Tags Expand 13 | Dynamic Programming, Array, Game Theory 14 | 15 | """ 16 | __author__ = 'Daniel' 17 | 18 | 19 | class Solution: 20 | def firstWillWin_MLE(self, values): 21 | """ 22 | Starting from back 23 | Memory Limit Exceeded 24 | 25 | let F_i^p represents maximum values he can get at index i, for the person p. 26 | 27 | F_i^0 = max(A_i + sum - F_{i+1}^1, # if choose one coin 28 | A_i + A_{i+1} + sum - F_{i+2}^1 # if choose two coin 29 | ) 30 | 31 | :param values: a list of integers 32 | :return: a boolean which equals to True if the first player will win 33 | """ 34 | n = len(values) 35 | if n <= 2: 36 | return True 37 | 38 | F = [[0 for _ in xrange(n)] for _ in xrange(2)] 39 | s = [0 for _ in xrange(n)] 40 | s[n-1] = values[n-1] 41 | for i in xrange(n-2, -1, -1): 42 | s[i] = values[i] + s[i+1] 43 | 44 | F[0][n-1] = F[1][n-1] = s[n-1] 45 | F[0][n-2] = F[1][n-2] = s[n-2] 46 | for i in xrange(n-3, -1, -1): 47 | for p in xrange(2): 48 | F[p][i] = max( 49 | values[i]+s[i+1]-F[1^p][i+1], 50 | values[i]+values[i+1]+s[i+2]-F[1^p][i+2] 51 | ) 52 | if F[0][0]>F[1][1] or F[0][0]>F[1][2]: 53 | return True 54 | return False 55 | 56 | def firstWillWin(self, values): 57 | """ 58 | Optimize the dp data structure 59 | Only size-4 data structure is needed to store the dp information. 60 | :param values: 61 | :return: 62 | """ 63 | n = len(values) 64 | if n <= 2: 65 | return True 66 | 67 | F = [[0 for _ in xrange(4)] for _ in xrange(2)] 68 | 69 | s = values[n-1] 70 | F[0][(n-1)%4] = F[1][(n-1)%4] = s 71 | 72 | s += values[n-2] 73 | F[0][(n-2)%4] = F[1][(n-2)%4] = s 74 | 75 | for i in xrange(n-3, -1, -1): 76 | for p in xrange(2): 77 | t = i%4 78 | F[p][t] = max( 79 | values[i]+s-F[1^p][(t+1)%4], 80 | values[i]+s-F[1^p][(t+2)%4] 81 | ) 82 | if i == 0: 83 | break 84 | 85 | s += values[i] 86 | 87 | t = 0 88 | if F[0][t] > F[1][(t+1)%4] or F[0][t] > F[1][(t+2)%4]: 89 | return True 90 | 91 | return False 92 | 93 | if __name__ == "__main__": 94 | values = [16,27,25,23,25,16,12,9,1,2,7,20,19,23,16,0,6,22,16,11,8,27,9,2,20,2,13,7,25,29,12,12,18,29,27,13,16,1,22, 95 | 9,3,21,29,14,7,8,14,5,0,23,16,1,20] 96 | assert Solution().firstWillWin(values)==True 97 | 98 | -------------------------------------------------------------------------------- /Coins in a Line.py: -------------------------------------------------------------------------------- 1 | """ 2 | There are n coins in a line. Two players take turns to take one or two coins from right side until there are no more 3 | coins left. The player who take the last coin wins. 4 | 5 | Could you please decide the first play will win or lose? 6 | 7 | Example 8 | n = 1, return true. 9 | n = 2, return true. 10 | n = 3, return false. 11 | n = 4, return true. 12 | n = 5, return true. 13 | 14 | Challenge 15 | O(1) time and O(1) memory 16 | """ 17 | __author__ = 'Daniel' 18 | 19 | 20 | class Solution: 21 | def firstWillWin(self, n): 22 | """ 23 | Starting from the easiest cases. 24 | Enumerate the cases and find the pattern 25 | 26 | :param n: an integer 27 | :return: a boolean which equals to True if the first player will win 28 | """ 29 | return not n%3 == 0 -------------------------------------------------------------------------------- /Compare Strings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Compare two strings A and B, determine whether A contains all of the characters in B. 3 | """ 4 | __author__ = 'Danyang' 5 | 6 | 7 | class Solution: 8 | def compareStrings(self, A, B): 9 | """ 10 | Straightforward 11 | 12 | :param A : A string includes Upper Case letters 13 | :param B : A string includes Upper Case letters 14 | :return : if string A contains all of the characters in B return True else return False 15 | """ 16 | cnt = [0 for _ in xrange(26)] 17 | for c in A: 18 | cnt[ord(c)-ord('A')] += 1 19 | for c in B: 20 | cnt[ord(c)-ord('A')] -= 1 21 | if cnt[ord(c)-ord('A')]<0: 22 | return False 23 | return True 24 | 25 | if __name__=="__main__": 26 | assert Solution().compareStrings("A", "")==True -------------------------------------------------------------------------------- /Container With Most Water.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are 3 | 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 4 | container, such that the container contains the most water. 5 | 6 | Example 7 | Given [1,3,2], the max area of the container is 2. 8 | 9 | Note 10 | You may not slant the container. 11 | """ 12 | __author__ = 'Daniel' 13 | 14 | 15 | class Solution(object): 16 | def maxArea(self, H): 17 | maxa = 0 18 | s = 0 19 | e = len(H) - 1 20 | while s < e: 21 | maxa = max(maxa, min(H[s], H[e])*(e-s)) 22 | if H[s] < H[e]: 23 | s += 1 24 | else: 25 | e -= 1 26 | 27 | return maxa 28 | 29 | 30 | -------------------------------------------------------------------------------- /Continuous Subarray Sum II.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array, find a continuous rotate subarray where the sum of numbers is the biggest. Your code should 3 | return the index of the first number and the index of the last number. (If their are duplicate answer, return anyone) 4 | 5 | Example 6 | Give [3, 1, -100, -3, 4], return [4,0]. 7 | """ 8 | __author__ = 'Daniel' 9 | from collections import namedtuple 10 | 11 | Sum = namedtuple("Sum", "sum i j") # data structure to store the sum and the starting and ending index. 12 | 13 | 14 | class Solution: 15 | def continuousSubarraySumII(self, A): 16 | """ 17 | 18 | :param A: 19 | :return: 20 | """ 21 | if len(A) < 1: 22 | return [-1, -1] 23 | linear = self.linear_max_sum(A) 24 | circular = self.circular_max_sum(A) 25 | if linear.sum > circular.sum: 26 | return [linear.i, linear.j] 27 | 28 | return [circular.i, circular.j] 29 | 30 | def circular_max_sum(self, A): 31 | """ 32 | dp: 33 | left: max sum for index 0..i 34 | right: max sum for index i..(n-1) 35 | 36 | :param A: 37 | :return: 38 | """ 39 | n = len(A) 40 | left = [None for _ in A] 41 | right = [None for _ in A] 42 | 43 | cur, max_sum, idx = 0, A[0], 0 44 | for i in xrange(n): 45 | cur += A[i] 46 | if cur > max_sum: 47 | idx = i 48 | max_sum = cur 49 | left[i] = (max_sum, idx) 50 | 51 | cur, max_sum, idx = 0, A[n-1], n-1 52 | for i in xrange(n-1, -1, -1): 53 | cur += A[i] 54 | if cur > max_sum: 55 | idx = i 56 | max_sum = cur 57 | right[i] = (max_sum, idx) 58 | 59 | ret = Sum(A[0], 0, 0) 60 | for i in xrange(1, n): 61 | r = right[i] 62 | l = left[i-1] 63 | if ret.sum < r[0]+l[0]: 64 | ret = Sum(r[0]+l[0], r[1], l[1]) 65 | 66 | return ret 67 | 68 | def linear_max_sum(self, A): 69 | """ 70 | Break at 0 71 | Same as Continuous Subrarry Sum I. 72 | 73 | :param A: an integer array 74 | :return: A list of integers includes the index of the first number and the index of the last number 75 | """ 76 | ret = Sum(A[0], 0, 0) 77 | 78 | cur = 0 # current sum 79 | s = 0 80 | for e, v in enumerate(A): 81 | cur += v 82 | if ret.sum < cur: 83 | ret = Sum(cur, s, e) 84 | 85 | if cur < 0: 86 | s = e+1 87 | cur = 0 88 | 89 | return ret 90 | 91 | if __name__ == "__main__": 92 | assert Solution().continuousSubarraySumII([3, 1, -100, -3, 4]) == [4, 1] 93 | assert Solution().continuousSubarraySumII([-5, 10, 5, -3, 1, 1, 1, -2, 3, -4]) == [1, 8] -------------------------------------------------------------------------------- /Continuous Subarray Sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array, find a continuous subarray where the sum of numbers is the biggest. Your code should return the 3 | index of the first number and the index of the last number. (If their are duplicate answer, return anyone) 4 | 5 | Example 6 | Give [-3, 1, 3, -3, 4], return [1,4]. 7 | """ 8 | __author__ = 'Daniel' 9 | from collections import namedtuple 10 | Sum = namedtuple("Sum", "sum i j") # data structure to store the sum and the starting and ending index. 11 | 12 | 13 | class Solution: 14 | def continuousSubarraySum(self, A): 15 | """ 16 | Break at 0 17 | 18 | :param A: an integer array 19 | :return: A list of integers includes the index of the first number and the index of the last number 20 | """ 21 | if len(A) < 1: 22 | return [-1, -1] 23 | 24 | ret = Sum(A[0], 0, 0) 25 | cur = 0 # current sum 26 | s = 0 27 | for e, v in enumerate(A): 28 | cur += v 29 | if ret.sum < cur: 30 | ret = Sum(cur, s, e) 31 | 32 | if cur < 0: 33 | s = e+1 34 | cur = 0 35 | 36 | return [ret.i, ret.j] 37 | 38 | 39 | if __name__ == "__main__": 40 | assert Solution().continuousSubarraySum( 41 | [-101, -33, -44, -55, -67, -78, -101, -33, -44, -55, -67, -78, -100, -200, -1000, -22, -100, -200, -1000, -22] 42 | ) == [15, 15] 43 | -------------------------------------------------------------------------------- /Convert Expression to Polish Notation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an expression string array, return the Polish notation of this expression. (remove the parentheses) 3 | 4 | Example 5 | For the expression [(5 -6) * 7] (which is represented by ["(", "5", "-", "6", ")", "*", "7"]), the corresponding polish 6 | notation is [* - 5 6 7] (which the return value should be ["*", "-", "5", "6", "7"]). 7 | """ 8 | __author__ = 'Daniel' 9 | 10 | 11 | class Solution: 12 | def convertToPN(self, expression): 13 | """ 14 | https://github.com/kamyu104/LintCode/blob/master/C%2B%2B/convert-expression-to-polish-notation.cpp 15 | need to reverse 16 | 17 | :param expression: A string list 18 | :return: The Polish notation of this expression 19 | """ 20 | return self.infix2prefix(expression) 21 | 22 | def infix2prefix(self, lst): 23 | """ 24 | starting from right the left 25 | """ 26 | stk = [] 27 | pre = [] 28 | for elt in reversed(lst): 29 | if elt.isdigit(): 30 | pre.append(elt) 31 | elif elt == ")": 32 | stk.append(elt) 33 | elif elt == "(": 34 | while stk and stk[-1] != ")": 35 | pre.append(stk.pop()) 36 | stk.pop() 37 | else: 38 | while stk and self.precedence(elt) < self.precedence(stk[-1]): # < rather than <= 39 | pre.append(stk.pop()) 40 | stk.append(elt) 41 | 42 | while stk: 43 | pre.append(stk.pop()) 44 | 45 | pre.reverse() 46 | return pre 47 | 48 | def precedence(self, x): 49 | if x in ("(", ")"): 50 | return 0 51 | if x in ("+", "-"): 52 | return 1 53 | if x in ("*", "/"): 54 | return 2 55 | return 3 56 | 57 | 58 | if __name__ == "__main__": 59 | assert Solution().infix2prefix(["(", "5", "-", "6", ")", "*", "7"]) == ['*', '-', '5', '6', '7'] -------------------------------------------------------------------------------- /Convert Expression to Reverse Polish Notation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an expression string array, return the Reverse Polish notation of this expression. (remove the parentheses) 3 | 4 | Example 5 | For the expression [3 - 4 + 5] (which denote by ["3", "-", "4", "+", "5"]), return [3 4 - 5 +] (which denote by ["3", 6 | "4", "-", "5", "+"]) 7 | """ 8 | __author__ = 'Daniel' 9 | 10 | 11 | class Solution(object): 12 | def convertToRPN(self, expression): 13 | """ 14 | 15 | :param expression: A string list 16 | :return: The Reverse Polish notation of this expression 17 | """ 18 | return self.infix2postfix(expression) 19 | 20 | def infix2postfix(self, lst): 21 | """ 22 | The stack temporarily stores the operators of strictly increasing precedence order. 23 | 24 | :param lst: 25 | :return: 26 | """ 27 | stk = [] 28 | ret = [] # post fix 29 | for elt in lst: 30 | if elt.isdigit(): 31 | ret.append(elt) 32 | elif elt == "(": 33 | stk.append(elt) 34 | elif elt == ")": 35 | while stk and stk[-1] != "(": 36 | ret.append(stk.pop()) 37 | stk.pop() # pop "(" 38 | else: 39 | while stk and self.precedence(elt) <= self.precedence(stk[-1]): 40 | ret.append(stk.pop()) 41 | stk.append(elt) 42 | 43 | while stk: # clean up 44 | ret.append(stk.pop()) 45 | 46 | return ret 47 | 48 | def precedence(self, x): 49 | if x in ("(", ")"): 50 | return 0 51 | if x in ("+", "-"): 52 | return 1 53 | if x in ("*", "/"): 54 | return 2 55 | return 3 56 | 57 | if __name__ == "__main__": 58 | print Solution().infix2postfix(["3", "-", "4", "+", "5"]) -------------------------------------------------------------------------------- /Convert Integer A to Integer B.py: -------------------------------------------------------------------------------- 1 | """ 2 | Determine the number of bits required to convert integer A to integer B 3 | 4 | Example 5 | Given n = 31, m = 14,return 2 6 | 7 | (31)10=(11111)2 8 | 9 | (14)10=(01110)2 10 | """ 11 | __author__ = 'Danyang' 12 | 13 | 14 | class Solution: 15 | def bitSwapRequired(self, a, b): 16 | """ 17 | 18 | :param a: 19 | :param b: 20 | :return: int 21 | """ 22 | a = self.to_bin(a) 23 | b = self.to_bin(b) 24 | diff = len(a)-len(b) 25 | ret = 0 26 | if diff<0: 27 | a, b = b, a 28 | diff *= -1 29 | b = "0"*diff+b 30 | for i in xrange(len(b)): 31 | if a[i]!=b[i]: 32 | ret += 1 33 | 34 | return ret 35 | 36 | def to_bin(self, n): 37 | """ 38 | 2's complement 39 | 32-bit 40 | :param n: 41 | :return: 42 | """ 43 | """ 44 | :param n: 45 | :return: 46 | """ 47 | a = abs(n) 48 | lst = [] 49 | while a>0: 50 | lst.append(a%2) 51 | a /= 2 52 | 53 | # 2's complement 54 | if n>=0: 55 | lst.extend([0]*(32-len(lst))) 56 | else: 57 | pivot = -1 58 | for i in xrange(len(lst)): 59 | if pivot==-1 and lst[i]==1: 60 | pivot = i 61 | continue 62 | if pivot!=-1: 63 | lst[i] ^= 1 64 | 65 | lst.extend([1]*(32-len(lst))) 66 | 67 | return "".join(map(str, reversed(lst))) 68 | 69 | if __name__=="__main__": 70 | assert Solution().bitSwapRequired(1, -1)==31 71 | assert Solution().bitSwapRequired(31, 14)==2 72 | 73 | -------------------------------------------------------------------------------- /Copy Books.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array A of integer with size of n( means n books and number of pages of each book) and k people to copy the 3 | book. You must distribute the continuous id books to one people to copy. (You can give book A[1],A[2] to one people, but 4 | you cannot give book A[1], A[3] to one people, because book A[1] and A[3] is not continuous.) Each person have can copy 5 | one page per minute. Return the number of smallest minutes need to copy all the books. 6 | 7 | Example 8 | Given array A = [3,2,4], k = 2. 9 | 10 | Return 5 (First person spends 5 minutes to copy book 1 and book 2 and second person spends 4 minutes to copy book 3.) 11 | 12 | Challenge 13 | Could you do this in O(n*k) time ? 14 | """ 15 | __author__ = 'Daniel' 16 | 17 | 18 | class Solution: 19 | def copyBooks(self, pages, k): 20 | """ 21 | DP: 22 | let F[i][j] be the smallest page count with the person[:i] copying the pages[:j] 23 | 24 | F[i][j] = min( 25 | max(F[i-1][t], sum(pages[t:j]) \forall t \in [0, j)) 26 | ) 27 | 28 | F[i][j] is monotonous w.r.t. both i and j 29 | 30 | left r pointers 31 | move left pointer if the previous people assigned less compared to current person 32 | move r pointer otherwise 33 | 34 | Complexity analysis: 35 | for each people, 36 | r forward at most n 37 | l backward at most n 38 | l forward at most 2n 39 | thus, O(n k) 40 | :type pages: List[int] 41 | :type k: int 42 | :rtype: int 43 | """ 44 | n = len(pages) 45 | s = [0 for _ in xrange(n+1)] 46 | for i in xrange(1, n+1): 47 | s[i] = s[i-1] + pages[i-1] 48 | 49 | F = [[s[j] for j in xrange(n+1)] for _ in xrange(k+1)] # initialize to upper limit 50 | 51 | for i in xrange(2, k+1): 52 | l = 0 # left 53 | r = 1 # right 54 | while r < n+1: 55 | F[i][r] = min(F[i][r], 56 | max(F[i-1][l], s[r]-s[l]) 57 | ) 58 | if F[i-1][l] < s[r]-s[l] and l < r: 59 | # assign less to current people 60 | l += 1 61 | else: 62 | # assign more to current people 63 | if l > 0: l -= 1 64 | r += 1 65 | 66 | return F[-1][-1] 67 | 68 | 69 | class Solution_TLE: 70 | def copyBooks(self, pages, k): 71 | """ 72 | DP: 73 | let F[i][j] be the smallest page count with the person[:i] copying the pages[:j] 74 | 75 | F[i][j] = min( 76 | max(F[i-1][t], sum(pages[t:j]) \forall t \in [0, j)) 77 | ) 78 | 79 | O(n^2 k) 80 | :type pages: List[int] 81 | :type k: int 82 | :rtype: int 83 | """ 84 | n = len(pages) 85 | s = [0 for _ in xrange(n+1)] 86 | for i in xrange(1, n+1): 87 | s[i] = s[i-1] + pages[i-1] 88 | 89 | F = [[s[j] for j in xrange(n+1)] for _ in xrange(k+1)] # initialize to upper limit 90 | 91 | for i in xrange(2, k+1): 92 | for j in xrange(1, n+1): 93 | F[i][j] = min( 94 | max(F[i-1][t], s[j]-s[t]) for t in xrange(j) 95 | ) 96 | 97 | return F[-1][-1] 98 | 99 | 100 | class Solution_search: 101 | def copyBooks(self, pages, k): 102 | """ 103 | :type pages: List[int] 104 | :type k: int 105 | :rtype: int 106 | """ 107 | return self.bisect(pages, k, sum(pages)/k, sum(pages)) 108 | 109 | def bisect(self, pages, k, lower, upper): 110 | """ 111 | O(n lg sum(p)) 112 | """ 113 | while lower < upper: 114 | mid = (lower+upper)/2 115 | if self.valid(pages, k, mid): 116 | upper = mid 117 | else: 118 | lower = mid+1 119 | 120 | return lower 121 | 122 | def valid(self, pages, k, limit): 123 | cnt = 0 124 | k -= 1 125 | for p in pages: 126 | if p > limit: return False 127 | 128 | cnt += p 129 | if cnt > limit: 130 | cnt = p 131 | k -= 1 132 | 133 | if k < 0: return False 134 | 135 | return True 136 | 137 | 138 | if __name__ == "__main__": 139 | assert Solution().copyBooks([3, 2], 5) == 3 -------------------------------------------------------------------------------- /Count of Smaller Number before itself.py: -------------------------------------------------------------------------------- 1 | """ 2 | Give you an integer array (index from 0 to n-1, where n is the size of this array, value from 0 to 10000) . For each 3 | element Ai in the array, count the number of element before this element Ai is smaller than it and return count number 4 | array. 5 | 6 | Example 7 | For array [1,2,7,8,5], return [0,1,2,3,2] 8 | 9 | Note 10 | We suggest you finish problem Segment Tree Build, Segment Tree Query II and Count of Smaller Number before itself I 11 | first. 12 | """ 13 | __author__ = 'Daniel' 14 | 15 | 16 | class Node(object): 17 | def __init__(self, lo, hi): 18 | """Records the left subtree size""" 19 | self.lo = lo 20 | self.hi = hi 21 | self.left = None 22 | self.right = None 23 | self.cnt_this = 0 24 | self.cnt_left = 0 25 | 26 | def __repr__(self): 27 | return repr("[%d, %d)" % (self.lo, self.hi)) 28 | 29 | 30 | class SegmentTree(object): 31 | def __init__(self): 32 | self.root = None 33 | 34 | def build(self, root, lo, hi): 35 | if lo >= hi: return 36 | if not root: root = Node(lo, hi) 37 | 38 | root.left = self.build(root.left, lo, (lo+hi)/2) 39 | if root.left: root.right = self.build(root.right, (lo+hi)/2, hi) 40 | 41 | return root 42 | 43 | def set(self, root, i, val): 44 | if root.lo == i and root.hi-1 == root.lo: 45 | root.cnt_this += val 46 | elif i < (root.lo+root.hi)/2: 47 | root.cnt_left += val 48 | self.set(root.left, i, val) 49 | else: 50 | self.set(root.right, i, val) 51 | 52 | def get(self, root, i): 53 | if root.lo == i and root.hi-1 == root.lo: 54 | return root.cnt_left 55 | elif i < (root.lo+root.hi)/2: 56 | return self.get(root.left, i) 57 | else: 58 | return root.cnt_left+root.cnt_this+self.get(root.right, i) 59 | 60 | 61 | class Solution(object): 62 | def _build_tree(self, A): 63 | st = SegmentTree() 64 | mini, maxa = min(A), max(A) 65 | st.root = st.build(st.root, mini, maxa+2) # maxa+1 is the end dummy 66 | return st 67 | 68 | def countOfSmallerNumberII(self, A): 69 | """ 70 | count of smaller number before it. 71 | Segment Tree 72 | 73 | :param A: A list of integer 74 | :return: Count the number of element before this element 'ai' is smaller than it and return count number list 75 | """ 76 | if not A: return [] 77 | st = self._build_tree(A) 78 | ret = [] 79 | for a in A: 80 | st.set(st.root, a, 1) 81 | ret.append( 82 | st.get(st.root, a) 83 | ) 84 | 85 | return ret 86 | 87 | def countOfLargerElementsBeforeElement(self, A): 88 | if not A: return [] 89 | st = self._build_tree(A) 90 | ret = [] 91 | end = max(A)+1 92 | for a in A: 93 | ret.append( 94 | st.get(st.root, end) - st.get(st.root, a) 95 | ) 96 | st.set(st.root, a, 1) 97 | 98 | return ret 99 | 100 | if __name__ == "__main__": 101 | assert Solution().countOfSmallerNumberII([1, 2, 7, 8, 5]) == [0, 1, 2, 3, 2] 102 | assert Solution().countOfLargerElementsBeforeElement([1, 9, 7, 8, 5]) == [0, 0, 1, 1, 3] 103 | assert Solution().countOfSmallerNumberII( 104 | [26, 78, 27, 100, 33, 67, 90, 23, 66, 5, 38, 7, 35, 23, 52, 22, 83, 51, 98, 69, 81, 32, 78, 28, 94, 13, 2, 97, 105 | 3, 76, 99, 51, 9, 21, 84, 66, 65, 36, 100, 41]) == [0, 1, 1, 3, 2, 3, 5, 0, 4, 0, 5, 1, 6, 2, 9, 2, 14, 10, 17, 106 | 14, 16, 7, 16, 7, 22, 2, 0, 25, 1, 20, 29, 15, 4, 6, 28, 107 | 20, 20, 16, 37, 18] 108 | -------------------------------------------------------------------------------- /Count of Smaller Number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Give you an integer array (index from 0 to n-1, where n is the size of this array, value from 0 to 10000) and an query 3 | list. For each query, give you an integer, return the number of element in the array that are smaller that the given 4 | integer. 5 | 6 | Example 7 | For array [1,2,7,8,5], and queries [1,8,5], return [0,4,2] 8 | 9 | Note 10 | We suggest you finish problem Segment Tree Build and Segment Tree Query II first. 11 | 12 | Challenge 13 | Could you use three ways to do it. 14 | 15 | Just loop 16 | Sort and binary search 17 | Build Segment Tree and Search. 18 | 19 | """ 20 | __author__ = 'Daniel' 21 | 22 | 23 | class Solution: 24 | def countOfSmallerNumber(self, A, queries): 25 | # return self.loop(A, queries) 26 | return self.search(A, queries) 27 | 28 | def loop(self, A, queries): 29 | """ 30 | O(N*k) 31 | """ 32 | cnt = dict(zip(queries, [0 for _ in queries])) 33 | for elt in A: 34 | for k in cnt.keys(): 35 | if elt=0 and A[ind]==q: 49 | ind -= 1 50 | ret.append(ind+1) 51 | 52 | return ret 53 | 54 | def bin_search(self, A, t): 55 | b = 0 56 | e = len(A) 57 | while b 0: 31 | if lst[i] > lst[i+1]: 32 | del lst[i] 33 | i -= 1 34 | if i < 0: 35 | i = 0 36 | k -= 1 37 | else: 38 | i += 1 39 | if k > 0: 40 | lst = lst[:len(lst)-k] 41 | 42 | return "".join(map(str, lst)).lstrip("0") 43 | 44 | def DeleteDigits_error(self, A, k): 45 | """ 46 | Remove and keep the n-k largest numbers 47 | heap: O(n lg (n-k)) 48 | 49 | error in case: 254193, 1 50 | 51 | :param A: A positive integer which has N digits, A is a string. 52 | :param k: Remove k digits. 53 | :return: A string 54 | """ 55 | lst = map(int, list(str(A))) 56 | m = len(lst)-k 57 | 58 | tuples = [(-lst[i], i) for i in xrange(m)] # negative sign for max heap 59 | heapq.heapify(tuples) 60 | for i in xrange(m, len(lst)): 61 | if -tuples[0][0] > lst[i]: 62 | heapq.heappop(tuples) 63 | heapq.heappush(tuples, (-lst[i], i)) 64 | 65 | rets = [elt[1] for elt in tuples] 66 | rets.sort() 67 | rets = map(lambda x: str(lst[x]), rets) 68 | return "".join(rets) 69 | 70 | 71 | if __name__ == "__main__": 72 | assert Solution().DeleteDigits(10009876091, 4) == "6091" 73 | 74 | 75 | -------------------------------------------------------------------------------- /Divide Two Integers.py: -------------------------------------------------------------------------------- 1 | """ 2 | Divide two integers without using multiplication, division and mod operator. 3 | 4 | If it is overflow, return 2147483647 5 | 6 | Example 7 | Given dividend = 100 and divisor = 9, return 11. 8 | """ 9 | __author__ = 'Daniel' 10 | 11 | 12 | class Solution: 13 | def divide(self, dividend, divisor): 14 | q = 0 15 | if dividend == 0 or divisor == 0: 16 | return 0 17 | 18 | # pitfall, overflow 19 | MAXINT = 2147483647 20 | MININT = -2147483648 21 | if dividend == MININT and divisor == -1: 22 | return MAXINT 23 | 24 | sign = 1 if dividend*divisor > 0 else -1 25 | dividend, divisor = abs(dividend), abs(divisor) 26 | 27 | d = divisor 28 | q_cur = 1 29 | if divisor > dividend: 30 | return 0 31 | 32 | while d<<1 < dividend: 33 | d <<= 1 34 | q_cur <<= 1 35 | 36 | q += q_cur 37 | dividend -= d 38 | 39 | while dividend: 40 | if divisor > dividend: 41 | break 42 | 43 | while d > dividend: 44 | d >>= 1 45 | q_cur >>= 1 46 | 47 | q += q_cur 48 | dividend -= d 49 | 50 | return q*sign 51 | 52 | if __name__ == "__main__": 53 | print Solution().divide(-1, 1) -------------------------------------------------------------------------------- /Evaluate Reverse Polish Notation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Evaluate the value of an arithmetic expression in Reverse Polish Notation. 3 | 4 | Valid operators are +, -, *, /. Each operand may be an integer or another expression. 5 | 6 | Have you met this question in a real interview? Yes 7 | Example 8 | ["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9 9 | ["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6 10 | """ 11 | __author__ = 'Daniel' 12 | 13 | 14 | class Solution: 15 | def evalRPN(self, tokens): 16 | """ 17 | Evaluate postfix. Negative numbers possible 18 | 19 | :param tokens: The Reverse Polish Notation 20 | :return: the value 21 | """ 22 | return self.eval_postfix(tokens) 23 | 24 | def eval_postfix(self, post): 25 | stk = [] 26 | for elt in post: 27 | if elt.strip("-").isdigit(): 28 | stk.append(int(elt)) 29 | else: 30 | b = stk.pop() 31 | a = stk.pop() 32 | if elt == "+": 33 | stk.append(a+b) 34 | elif elt == "-": 35 | stk.append(a-b) 36 | elif elt == "*": 37 | stk.append(a*b) 38 | else: 39 | stk.append(self.__div(a, b)) # 6/-132 should be evaluated to 0 as C-like 40 | 41 | if stk: 42 | return stk[-1] 43 | return 0 44 | 45 | 46 | def __div(self, a, b): 47 | sign = 1 48 | if a*b < 0: 49 | sign = -1 50 | 51 | return abs(a)/abs(b)*sign -------------------------------------------------------------------------------- /Expression Evaluation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an expression string array, return the final result of this expression 3 | 4 | Example 5 | For the expression 2*6-(23+7)/(1+2), input is 6 | 7 | [ 8 | "2", "*", "6", "-", "(", 9 | "23", "+", "7", ")", "/", 10 | (", "1", "+", "2", ")" 11 | ], 12 | return 2 13 | 14 | Note 15 | The expression contains only integer, +, -, *, /, (, ). 16 | """ 17 | __author__ = 'Daniel' 18 | 19 | 20 | class Solution: 21 | def evaluateExpression(self, expression): 22 | """ 23 | List + Stack 24 | 25 | a individual number has the highest precedence 26 | 27 | postfix is in increasing precedence order 28 | :param expression: a list of strings; 29 | :return: an integer 30 | """ 31 | post = self.infix2postfix(expression) 32 | return self.eval_postfix(post) 33 | 34 | def infix2postfix(self, lst): 35 | stk = [] 36 | post = [] # post fix expression with increasing precedence order 37 | for elt in lst: 38 | if elt.isdigit(): 39 | post.append(elt) 40 | else: 41 | if elt == "(": 42 | stk.append(elt) 43 | elif elt == ")": 44 | while stk and stk[-1] != "(": 45 | post.append(stk.pop()) 46 | stk.pop() # pop "(" 47 | else: 48 | while stk and self.precedence(elt) <= self.precedence(stk[-1]): 49 | post.append(stk.pop()) 50 | stk.append(elt) 51 | 52 | while stk: 53 | post.append(stk.pop()) 54 | 55 | return post 56 | 57 | def eval_postfix(self, post): 58 | stk = [] 59 | for elt in post: 60 | if elt.isdigit(): 61 | stk.append(int(elt)) 62 | else: 63 | b = stk.pop() 64 | a = stk.pop() 65 | if elt == "+": 66 | stk.append(a+b) 67 | elif elt == "-": 68 | stk.append(a-b) 69 | elif elt == "*": 70 | stk.append(a*b) 71 | else: 72 | stk.append(a/b) 73 | 74 | if stk: 75 | return stk[-1] 76 | return 0 77 | 78 | def precedence(self, a): 79 | if a in ("(", ")"): 80 | return 0 81 | if a in ("+", "-"): 82 | return 1 83 | if a in ("*", "/"): 84 | return 2 85 | return 3 86 | 87 | 88 | if __name__ == "__main__": 89 | t = [ 90 | "2", "*", "6", "-", "(", 91 | "23", "+", "7", ")", "/", 92 | "(", "1", "+", "2", ")" 93 | ] 94 | assert Solution().evaluateExpression(list("1+5")) == 6 95 | assert Solution().evaluateExpression(t)==2 -------------------------------------------------------------------------------- /Expression Tree Build.py: -------------------------------------------------------------------------------- 1 | """ 2 | The structure of Expression Tree is a binary tree to evaluate certain expressions. All leaves of the Expression Tree 3 | have an number string value. All non-leaves of the Expression Tree have an operator string value. 4 | 5 | Now, given an expression array, build the expression tree of this expression, return the root of this expression tree. 6 | 7 | Example 8 | For the expression (2*6-(23+7)/(1+2)) (which can be represented by ["2" "*" "6" "-" "(" "23" "+" "7" ")" "/" "(" "1" "+" 9 | "2" ")"]). The expression tree will be like 10 | 11 | [ - ] 12 | / \ 13 | [ * ] [ / ] 14 | / \ / \ 15 | [ 2 ] [ 6 ] [ + ] [ + ] 16 | / \ / \ 17 | [ 23 ][ 7 ] [ 1 ] [ 2 ] . 18 | After building the tree, you just need to return root node [-]. 19 | """ 20 | __author__ = 'Daniel' 21 | 22 | 23 | class ExpressionTreeNode: 24 | def __init__(self, symbol): 25 | self.symbol = symbol 26 | self.left, self.right = None, None 27 | 28 | 29 | class Solution: 30 | def build(self, expression): 31 | """ 32 | 33 | :param expression: A string list 34 | :return: The root of expression tree 35 | """ 36 | post = self.infix2postfix(expression) 37 | tree_node = self.postfix2tree(post) 38 | return tree_node 39 | 40 | def infix2postfix(self, expression): 41 | """ 42 | 43 | :param expression: 44 | :return: 45 | """ 46 | post = [] 47 | op_stk = [] 48 | for elt in expression: 49 | if elt.isdigit(): 50 | post.append(elt) 51 | elif elt == "(": 52 | op_stk.append(elt) 53 | elif elt == ")": 54 | while op_stk and op_stk[-1] != "(": 55 | post.append(op_stk.pop()) 56 | op_stk.pop() 57 | else: 58 | while op_stk and self.precedence(op_stk[-1]) >= self.precedence( 59 | elt): # notice equal for the order of operators of same precedence. 60 | post.append(op_stk.pop()) 61 | op_stk.append(elt) 62 | 63 | while op_stk: 64 | post.append(op_stk.pop()) 65 | 66 | return post 67 | 68 | def postfix2tree(self, post): 69 | tree_stk = [] 70 | for elt in post: 71 | if elt.isdigit(): 72 | tree_stk.append(ExpressionTreeNode(elt)) 73 | else: 74 | pi = ExpressionTreeNode(elt) 75 | pi.right = tree_stk.pop() 76 | pi.left = tree_stk.pop() 77 | tree_stk.append(pi) 78 | 79 | try: 80 | return tree_stk.pop() 81 | except IndexError: 82 | return None 83 | 84 | def precedence(self, elt): 85 | if elt in ("(", ")"): 86 | return 0 87 | if elt in ("+", "-"): 88 | return 1 89 | if elt in ("*", "/"): 90 | return 2 91 | return 3 92 | 93 | 94 | if __name__ == "__main__": 95 | tree_ndoe = Solution().build(["2", "*", "6", "-", "(", "23", "+", "7", ")", "/", "(", "1", "+", "2", ")"]) 96 | assert tree_ndoe.symbol == "-" -------------------------------------------------------------------------------- /Fibonacci.py: -------------------------------------------------------------------------------- 1 | """ 2 | Find the Nth number in Fibonacci sequence. 3 | 4 | A Fibonacci sequence is defined as follow: 5 | 6 | The first two numbers are 0 and 1. 7 | The i th number is the sum of i-1 th number and i-2 th number. 8 | The first ten numbers in Fibonacci sequence is: 9 | 10 | 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ... 11 | 12 | Have you met this question in a real interview? Yes 13 | Example 14 | Given 1, return 0 15 | 16 | Given 2, return 1 17 | 18 | Given 10, return 34 19 | 20 | Note 21 | The Nth fibonacci number won't exceed the max value of signed 32-bit integer in the test cases. 22 | """ 23 | __author__ = 'Daniel' 24 | 25 | 26 | class Solution: 27 | def fibonacci(self, n): 28 | """ 29 | For loop in a functional way 30 | :param n: an integer 31 | :return: an integer f(n) 32 | """ 33 | f = lambda n: reduce(lambda x, n: [x[1], x[0]+x[1]], range(n), [0, 1])[0] # reduce(func, itr, accumulator) 34 | return f(n-1) -------------------------------------------------------------------------------- /Find Peak Element II.py: -------------------------------------------------------------------------------- 1 | """ 2 | There is an integer matrix which has the following features: 3 | 4 | The numbers in adjacent positions are different. 5 | The matrix has n rows and m columns. 6 | For all i < m, A[0][i] < A[1][i] && A[n - 2][i] > A[n - 1][i]. 7 | For all j < n, A[j][0] < A[j][1] && A[j][m - 2] > A[j][m - 1]. 8 | We define a position P is a peek if A[j][i] > A[j+1][i] && A[j][i] > A[j-1][i] && A[j][i] > A[j][i+1] && A[j][i] > 9 | A[j][i-1]. 10 | 11 | Find a peak element in this matrix. Return the index of the peak. 12 | 13 | Example 14 | Given a matrix: 15 | 16 | [ 17 | [1 ,2 ,3 ,6 ,5], 18 | [16,41,23,22,6], 19 | [15,17,24,21,7], 20 | [14,18,19,20,10], 21 | [13,14,11,10,9] 22 | ] 23 | return index of 41 (which is [1,1]) or index of 24 (which is [2,2]) 24 | 25 | Note 26 | The matrix may contains multiple peeks, find any of them. 27 | 28 | Challenge 29 | Solve it in O(n+m) time. 30 | 31 | If you come up with an algorithm that you thought it is O(n log m) or O(m log n), can you prove it is actually O(n+m) or 32 | propose a similar but O(n+m) algorithm? 33 | """ 34 | import sys 35 | 36 | __author__ = 'Daniel' 37 | 38 | 39 | class Solution: 40 | def findPeakII(self, A): 41 | """ 42 | T(m, n) = T(m, n/2) + O(m) = T(m/2, n/2) + O(m) + O(n/2) = ... = O(m+n) 43 | 44 | Dimension reduction: Project 2D to 1D by representing the column vector using the representative item 45 | 46 | :param A: An list of list integer 47 | :return: The index of position is a list of integer, for example [2,2] 48 | """ 49 | minint = -sys.maxint-1 50 | 51 | left = 0 52 | right = len(A[0]) 53 | top = 0 54 | bottom = len(A) 55 | 56 | while left < right and top < bottom: 57 | if right-left > bottom-top: 58 | mid = (right+left)/2 59 | l_max = minint # left 60 | r_max = minint # right 61 | c_max = minint # center 62 | c_i, c_j = -1, -1 # for c_max 63 | for i in xrange(top, bottom): 64 | l_max = max(l_max, A[i][mid-1]) 65 | r_max = max(r_max, A[i][mid+1]) 66 | c_max = max(c_max, A[i][mid]) 67 | if c_max == A[i][mid]: 68 | c_i, c_j = i, mid 69 | 70 | if l_max > c_max and l_max > r_max: 71 | right = mid 72 | elif r_max > c_max and r_max > l_max: 73 | left = mid+1 74 | else: 75 | return [c_i, c_j] 76 | 77 | else: 78 | mid = (top+bottom)/2 79 | u_max = minint # up 80 | d_max = minint # down 81 | c_max = minint # center 82 | c_i, c_j = -1, -1 83 | for j in xrange(left, right): 84 | u_max = max(u_max, A[mid-1][j]) 85 | d_max = max(d_max, A[mid+1][j]) 86 | c_max = max(c_max, A[mid][j]) 87 | if c_max == A[mid][j]: 88 | c_i, c_j = mid, j 89 | 90 | if u_max > c_max and u_max > d_max: 91 | bottom = mid 92 | elif d_max > c_max and d_max > u_max: 93 | top = mid+1 94 | else: 95 | return [c_i, c_j] 96 | 97 | return [-1, -1] 98 | 99 | 100 | if __name__ == "__main__": 101 | A = [ 102 | [1, 2, 3, 4, 5, 6], 103 | [14, 15, 16, 17, 18, 8], 104 | [12, 13, 11, 10, 9, 7] 105 | ] 106 | 107 | print Solution().findPeakII(A) -------------------------------------------------------------------------------- /Find Peak Element.py: -------------------------------------------------------------------------------- 1 | """ 2 | There is an integer array which has the following features: 3 | 4 | * The numbers in adjacent positions are different. 5 | 6 | * A[0] < A[1] && A[A.length - 2] > A[A.length - 1]. 7 | 8 | We define a position P is a peek if A[P] > A[P-1] && A[P] > A[P+1]. 9 | 10 | Find a peak in this array. Return the index of the peak. 11 | 12 | Note 13 | The array may contains multiple peeks, find any of them. 14 | 15 | Example 16 | [1, 2, 1, 3, 4, 5, 7, 6] 17 | 18 | return index 1 (which is number 2) or 6 (which is number 7) 19 | 20 | Challenge 21 | Time complexity O(logN) 22 | """ 23 | __author__ = 'Danyang' 24 | 25 | 26 | class Solution: 27 | def findPeak(self, A): 28 | """ 29 | Binary search 30 | Microsoft Interview, Oct 2014 31 | 32 | To reduce the complexity of dealing the edge cases: 33 | * add two anti-peak dummies on the both ends 34 | 35 | :param A: An integers list. A[0] and A[-1] are dummies. 36 | :return: return any of peek positions. 37 | """ 38 | n = len(A) 39 | l = 0 40 | h = n 41 | while l < h: 42 | m = (l+h)/2 43 | if A[m-1] < A[m] > A[m+1]: 44 | return m 45 | elif A[m+1] > A[m]: 46 | l = m+1 47 | else: 48 | h = m 49 | 50 | raise Exception # will not raise if there are DUMMIES at the both ends. 51 | 52 | 53 | if __name__ == "__main__": 54 | assert Solution().findPeak([1, 2, 1, 3, 4, 5, 7, 6]) in (1, 6) 55 | 56 | -------------------------------------------------------------------------------- /Find the Connected Component in the Undirected Graph.py: -------------------------------------------------------------------------------- 1 | """ 2 | Find the number connected component in the undirected graph. Each node in the graph contains a label and a list of its 3 | neighbors. (a connected component (or just component) of an undirected graph is a subgraph in which any two vertices are 4 | connected to each other by paths, and which is connected to no additional vertices in the supergraph.) 5 | 6 | Note 7 | Sort the element in the set in increasing order 8 | """ 9 | __author__ = 'Daniel' 10 | 11 | 12 | class UndirectedGraphNode: 13 | def __init__(self, x): 14 | self.label = x 15 | self.neighbors = [] 16 | 17 | 18 | class Solution: 19 | def connectedSet(self, nodes): 20 | """ 21 | Connected component rather than clique 22 | 23 | :param nodes: {UndirectedGraphNode[]} nodes a array of undirected graph node 24 | :return: {int[][]} a connected set of a undirected graph 25 | """ 26 | rets = [] 27 | visisted = set() 28 | for node in nodes: 29 | if node not in visisted: 30 | ret = [] 31 | self.dfs(node, visisted, ret) 32 | ret.sort() 33 | rets.append(ret) 34 | 35 | return rets 36 | 37 | def dfs(self, node, visited, ret): 38 | # pre-call check 39 | ret.append(node.label) 40 | visited.add(node) 41 | for nei in node.neighbors: 42 | if nei not in visited: 43 | self.dfs(nei, visited, ret) 44 | -------------------------------------------------------------------------------- /Find the Missing Number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array contains N numbers of 0 .. N, find which number doesn't exist in the array. 3 | 4 | Example 5 | Given N = 3 and the array [0, 1, 3], return 2. 6 | 7 | Challenge 8 | Do it in-place with O(1) extra memory and O(n) time. 9 | """ 10 | __author__ = 'Daniel' 11 | 12 | 13 | class Solution(object): 14 | def findMissing(self, nums): 15 | """ 16 | in-place 17 | 18 | O(N) 19 | once an elt is inplace, it never moves 20 | """ 21 | nth = -1 22 | n = len(nums) 23 | i = 0 24 | while i < n: 25 | if nums[i] == n: 26 | nth = nums[i] 27 | i += 1 28 | elif nums[i] != i: 29 | nums[nums[i]], nums[i] = nums[i], nums[nums[i]] # complex first 30 | # nums[i], nums[nums[i]] = nums[nums[i]], nums[i] # evaluation order 31 | else: 32 | i += 1 33 | 34 | if nth == -1: 35 | return n 36 | else: 37 | return nums.index(nth) 38 | 39 | 40 | if __name__ == "__main__": 41 | print Solution().findMissing([9,8,7,6,2,0,1,5,4]) 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Find the Weak Connected Component in the Directed Graph.py: -------------------------------------------------------------------------------- 1 | """ 2 | Find the number Weak Connected Component in the directed graph. Each node in the graph contains a label and a list of 3 | its neighbors. (a connected set of a directed graph is a subgraph in which any two vertices are connected by direct edge 4 | path.) 5 | 6 | Example 7 | Given graph: 8 | 9 | A----->B C 10 | \ | | 11 | \ | | 12 | \ | | 13 | \ v v 14 | ->D E <- F 15 | Return {A,B,D}, {C,E,F}. Since there are two connected component which are {A,B,D} and {C,E,F} 16 | 17 | Note 18 | Sort the element in the set in increasing order 19 | """ 20 | 21 | 22 | class DirectedGraphNode: 23 | def __init__(self, x): 24 | self.label = x 25 | self.neighbors = [] 26 | 27 | def __repr__(self): 28 | return repr(self.x) 29 | 30 | from collections import defaultdict 31 | __author__ = 'Daniel' 32 | 33 | 34 | class UnionFind(object): 35 | """ 36 | Weighted Union Find with path compression 37 | """ 38 | def __init__(self): 39 | self.pi = {} # item -> pi 40 | self.sz = {} # root -> size 41 | 42 | def add(self, item): 43 | if item not in self.pi: 44 | self.pi[item] = item 45 | self.sz[item] = 1 46 | 47 | def union(self, a, b): 48 | pi1 = self._pi(a) 49 | pi2 = self._pi(b) 50 | 51 | if pi1 != pi2: 52 | if self.sz[pi1] > self.sz[pi2]: 53 | pi1, pi2 = pi2, pi1 54 | 55 | self.pi[pi1] = pi2 56 | self.sz[pi2] += self.sz[pi1] 57 | del self.sz[pi1] 58 | 59 | def _pi(self, item): 60 | pi = self.pi[item] 61 | if item != pi: 62 | self.pi[item] = self._pi(pi) 63 | 64 | return self.pi[item] 65 | 66 | def compress(self): 67 | for item in self.pi.keys(): 68 | self.pi[item] = self._pi(item) 69 | 70 | def count(self): 71 | return len(self.sz) # only root nodes have size 72 | 73 | 74 | class Solution: 75 | def connectedSet2(self, nodes): 76 | """ 77 | Union-find 78 | 79 | :param nodes: {DirectedGraphNode[]} nodes a array of directed graph node 80 | :return: {int[][]} a connected set of a directed graph 81 | """ 82 | uf = UnionFind() 83 | for node in nodes: 84 | uf.add(node.label) 85 | for nei in node.neighbors: 86 | uf.add(nei.label) 87 | uf.union(node.label, nei.label) 88 | 89 | uf.compress() 90 | ret = defaultdict(list) 91 | for item, pi in uf.pi.items(): 92 | ret[pi].append(item) 93 | 94 | for v in ret.values(): 95 | v.sort() 96 | 97 | return ret.values() 98 | 99 | if __name__ == "__main__": 100 | items = {i: DirectedGraphNode(i) for i in "ABCDEF"} 101 | items["A"].neighbors.append(items["B"]) 102 | items["A"].neighbors.append(items["D"]) 103 | items["B"].neighbors.append(items["D"]) 104 | items["C"].neighbors.append(items["E"]) 105 | items["F"].neighbors.append(items["E"]) 106 | assert Solution().connectedSet2(items.values()) == [['A', 'B', 'D'], ['C', 'E', 'F']] 107 | 108 | -------------------------------------------------------------------------------- /First Bad Version.py: -------------------------------------------------------------------------------- 1 | """ 2 | The code base version is an integer and start from 1 to n. One day, someone commit a bad version in the code case, so 3 | it caused itself and the following versions are all failed in the unit tests. 4 | """ 5 | __author__ = 'Danyang' 6 | 7 | 8 | class VersionControl: 9 | @classmethod 10 | def isBadVersion(cls, id): 11 | return True 12 | 13 | 14 | class Solution: 15 | def findFirstBadVersion(self, n): 16 | """ 17 | 18 | :param n: An integers. 19 | :return: An integer which is the first bad version. 20 | """ 21 | l = 1 22 | h = n+1 23 | while l < h: 24 | m = (l+h)/2 25 | if not VersionControl.isBadVersion(m): 26 | l = m+1 27 | else: 28 | h = m 29 | 30 | return l 31 | 32 | 33 | -------------------------------------------------------------------------------- /First Missing Positive.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an unsorted integer array, find the first missing positive integer. 3 | 4 | Example 5 | Given [1,2,0] return 3, and [3,4,-1,1] return 2. 6 | 7 | Challenge 8 | Your algorithm should run in O(n) time and uses constant space. 9 | """ 10 | __author__ = 'Daniel' 11 | 12 | 13 | class Solution(object): 14 | def firstMissingPositive(self, A): 15 | n = len(A) 16 | i = 0 17 | while i < n: 18 | v = A[i] 19 | if v <= 0 or v > n: 20 | i += 1 21 | elif A[v-1] != v: 22 | A[v-1], A[i] = v, A[v-1] 23 | else: 24 | i += 1 25 | 26 | for i in xrange(n): 27 | if A[i] != i+1: 28 | return i+1 29 | 30 | return n+1 31 | 32 | 33 | if __name__ == "__main__": 34 | assert Solution().firstMissingPositive([3, 4, -1, 1]) == 2 -------------------------------------------------------------------------------- /Hash Function.py: -------------------------------------------------------------------------------- 1 | """ 2 | In data structure Hash, hash function is used to convert a string(or any other type) into an integer smaller than hash 3 | size and bigger or equal to zero. The objective of designing a hash function is to "hash" the key as unreasonable as 4 | possible. A good hash function can avoid collision as less as possible. A widely used hash function algorithm is using 5 | a magic number 33 6 | """ 7 | __author__ = 'Danyang' 8 | 9 | 10 | class Solution: 11 | def hashCode(self, key, HASH_SIZE): 12 | """ 13 | :param key: A String you should hash 14 | :param HASH_SIZE: An integer 15 | :return an integer 16 | """ 17 | w = 1 18 | ret = 0 19 | for i in xrange(len(key)-1, -1, -1): 20 | ret = (ret+ord(key[i])*w)%HASH_SIZE 21 | w = (w*33)%HASH_SIZE 22 | return ret 23 | 24 | 25 | if __name__ == "__main__": 26 | assert Solution().hashCode("abcd", 100) == 78 27 | 28 | -------------------------------------------------------------------------------- /Heapify.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array, heapify it into a min-heap array. 3 | For a heap array A, A[0] is the root of heap, and for each A[i], A[i * 2 + 1] is the left child of A[i] and A[i * 2 + 2] 4 | is the right child of A[i]. 5 | Example 6 | Given [3,2,1,4,5], return [1,2,3,4,5] or any legal heap array. 7 | 8 | Challenge 9 | O(n) time complexity 10 | """ 11 | __author__ = 'Danyang' 12 | 13 | 14 | class Solution: 15 | def heapify(self, A): 16 | """ 17 | CLRS 18 | 19 | Min-heap generally is more common 20 | 21 | Heapify got multiple heappush 22 | Bottom up construction 23 | * Every leaf in heap is already a heap 24 | 25 | Strictly O(n) rather than O(nlg n) CLRS 6.3 building a heap 26 | for understanding: http://www.zhihu.com/question/20729324 27 | 28 | :param A: Given an integer array 29 | :return: 30 | """ 31 | n = len(A) 32 | for i in xrange(n/2, -1, -1): 33 | self.heappush(A, i) 34 | 35 | def heappush(self, A, i): 36 | """ 37 | heappush: heap push down 38 | 39 | Swap to the target position and push down 40 | 41 | T(n) = T(2n/3)+O(1) 42 | 43 | :param A: the array 44 | :param i: the index 45 | :return: 46 | """ 47 | n = len(A) 48 | if i >= n: 49 | return 50 | 51 | l = 2*i+1 52 | r = 2*i+2 53 | mini = i 54 | if l < n and A[l] < A[mini]: 55 | mini = l 56 | if r < n and A[r] < A[mini]: 57 | mini = r 58 | if i != mini: 59 | A[i], A[mini] = A[mini], A[i] 60 | swapped = mini 61 | self.heappush(A, swapped) 62 | 63 | def heapify_error(self, A, i=0): 64 | """ 65 | Erroneous solution 66 | 67 | :param A: Given an integer array 68 | :return: 69 | """ 70 | n = len(A) 71 | if i >= n: 72 | return 73 | 74 | l = 2*i+1 75 | r = 2*i+2 76 | mini = i 77 | if l < n and A[l] < A[mini]: 78 | mini = l 79 | if r < n and A[r] < A[mini]: 80 | mini = r 81 | A[i], A[mini] = A[mini], A[i] 82 | self.heapify_error(A, l) 83 | self.heapify_error(A, r) 84 | 85 | 86 | if __name__ == "__main__": 87 | A = [45, 39, 32, 11] 88 | Solution().heapify(A) 89 | assert A == [11, 39, 32, 45] 90 | -------------------------------------------------------------------------------- /Implement Iterator of Binary Search Tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Design an iterator over a binary search tree with the following properties: 3 | Elements are visited in ascending order (i.e. an inorder traversal) 4 | next() and hasNext() queries run in O(1) time in average. 5 | Example 6 | For the following binary search tree, inorder traversal by using iterator is [1, 6, 10, 11, 12] 7 | 8 | 10 9 | 10 | / \ 11 | 12 | 1 11 13 | 14 | \ \ 15 | 16 | 6 12 17 | 18 | 19 | 20 | Challenge 21 | Extra memory usage O(h), h is the height of the tree. 22 | Super Star: Extra memory usage O(1) 23 | """ 24 | __author__ = 'Danyang' 25 | 26 | 27 | class TreeNode: 28 | def __init__(self, val): 29 | self.val = val 30 | self.left, self.right = None, None 31 | 32 | 33 | class Solution: 34 | def __init__(self, root): 35 | """ 36 | O(h) memory 37 | memory usage 2h 38 | 39 | 40 | :param root: 41 | :return: 42 | """ 43 | self.stk = [] 44 | self.cur = root 45 | 46 | def hasNext(self): 47 | """ 48 | 49 | :return: True if there has next node, or False 50 | """ 51 | return self.cur or self.stk 52 | 53 | def next(self): 54 | """ 55 | In-order traversal: 1 stack 56 | reference: 57 | https://github.com/zhangdanyangg/LeetCode/blob/master/095%20Binary%20Tree%20Inorder%20Traversal.py 58 | 59 | :return: next node 60 | """ 61 | if not self.hasNext(): 62 | return None 63 | 64 | while self.cur: 65 | self.stk.append(self.cur) 66 | self.cur = self.cur.left 67 | 68 | node = self.stk.pop() # left_most 69 | self.cur = node.right 70 | return node -------------------------------------------------------------------------------- /Implement Queue by Stacks.py: -------------------------------------------------------------------------------- 1 | """ 2 | As the title described, you should only use two stacks to implement a queue's actions. 3 | 4 | The queue should support push(element), pop() and top() where pop is pop the first(a.k.a front) element in the queue. 5 | 6 | Both pop and top methods should return the value of first element. 7 | 8 | Example 9 | For push(1), pop(), push(2), push(3), top(), pop(), you should return 1, 2 and 2 10 | 11 | Challenge 12 | implement it by two stacks, do not use any other data structure and push, pop and top should be O(1) by AVERAGE. 13 | """ 14 | __author__ = 'Danyang' 15 | 16 | 17 | class Queue: 18 | def __init__(self): 19 | """ 20 | Dual stack 21 | """ 22 | self.in_stk = [] 23 | self.out_stk = [] 24 | 25 | def push(self, element): 26 | self.in_stk.append(element) 27 | 28 | def top(self): 29 | if not self.out_stk: 30 | while self.in_stk: 31 | self.out_stk.append(self.in_stk.pop()) 32 | 33 | return self.out_stk[-1] 34 | 35 | def pop(self): 36 | if not self.out_stk: 37 | while self.in_stk: 38 | self.out_stk.append(self.in_stk.pop()) 39 | 40 | return self.out_stk.pop() 41 | 42 | -------------------------------------------------------------------------------- /Insert Node in a Binary Search Tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary search tree and a new tree node, insert the node into the tree. You should keep the tree still be a 3 | valid binary search tree. 4 | 5 | Example 6 | Given binary search tree as follow: 7 | 8 | 2 9 | 10 | / \ 11 | 12 | 1 4 13 | 14 | / 15 | 16 | 3 17 | 18 | after Insert node 6, the tree should be: 19 | 20 | 2 21 | 22 | / \ 23 | 24 | 1 4 25 | 26 | / \ 27 | 28 | 3 6 29 | 30 | Challenge 31 | Do it without recursion 32 | """ 33 | __author__ = 'Danyang' 34 | 35 | 36 | class TreeNode: 37 | def __init__(self, val): 38 | self.val = val 39 | self.left, self.right = None, None 40 | 41 | 42 | class Solution: 43 | def insertNode(self, root, node): 44 | """ 45 | Insertion without balance should be straightforward 46 | 47 | :param root: The root of the binary search tree. 48 | :param node: insert this node into the binary search tree. 49 | :return: The root of the new binary search tree. 50 | """ 51 | cur = root 52 | if not root: 53 | root = node 54 | return root 55 | 56 | while cur: 57 | if cur.val == node.val: 58 | return root 59 | elif cur.val > node.val: 60 | if cur.left: 61 | cur = cur.left 62 | else: 63 | cur.left = node 64 | return root 65 | else: 66 | if cur.right: 67 | cur = cur.right 68 | else: 69 | cur.right = node 70 | return root 71 | 72 | 73 | -------------------------------------------------------------------------------- /Interleaving Positive and Negative Numbers.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array with positive and negative integers. Re-range it to interleaving with positive and negative integers. 3 | 4 | Have you met this question in a real interview? Yes 5 | Example 6 | Given [-1, -2, -3, 4, 5, 6], after re-range, it will be [-1, 5, -2, 4, -3, 6] or any other reasonable answer. 7 | 8 | Note 9 | You are not necessary to keep the original order of positive integers or negative integers. 10 | 11 | Challenge 12 | Do it in-place and without extra memory. 13 | """ 14 | __author__ = 'Daniel' 15 | 16 | 17 | class Solution(object): 18 | def rerange(self, A): 19 | """ 20 | Algorithm: Two Pointers 21 | :type A: List[int] 22 | :rtype: None, in-place 23 | """ 24 | n = len(A) 25 | pos_cnt = len(filter(lambda x: x > 0, A)) 26 | # expecting positive 27 | pos_expt = True if pos_cnt*2 > n else False 28 | 29 | neg = 0 # next negative 30 | pos = 0 # next positive 31 | for i in xrange(n): 32 | while neg < n and A[neg] > 0: neg += 1 33 | while pos < n and A[pos] < 0: pos += 1 34 | if pos_expt: 35 | A[i], A[pos] = A[pos], A[i] 36 | else: 37 | A[i], A[neg] = A[neg], A[i] 38 | 39 | if i == neg: neg += 1 40 | if i == pos: pos += 1 41 | 42 | pos_expt = not pos_expt 43 | 44 | 45 | if __name__ == "__main__": 46 | A = [-33, -19, 30, 26, 21, -9] 47 | Solution().rerange(A) 48 | assert A == [-33, 30, -19, 26, -9, 21] -------------------------------------------------------------------------------- /Interval Minimum Number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Hard Interval Minimum Number 3 | 4 | Given an integer array (index from 0 to n-1, where n is the size of this array), and an query list. Each query has two 5 | integers [start, end]. For each query, calculate the minimum number between index start and end in the given array, 6 | return the result list. 7 | 8 | Example 9 | For array [1,2,7,8,5], and queries [(1,2),(0,4),(2,4)], return [2,1,5] 10 | 11 | Note 12 | We suggest you finish problem Segment Tree Build, Segment Tree Query and Segment Tree Modify first. 13 | 14 | Challenge 15 | O(logN) time for each query 16 | """ 17 | __author__ = 'Daniel' 18 | import sys 19 | 20 | DEFAULT = sys.maxint 21 | f = lambda x, y: min(x, y) 22 | 23 | 24 | class Node(object): 25 | def __init__(self, start, end, m): 26 | self.start, self.end, self.m = start, end, m 27 | self.left, self.right = None, None 28 | 29 | 30 | class SegmentTree(object): 31 | def __init__(self, A): 32 | self.A = A 33 | self.root = self.build_tree(0, len(self.A)) 34 | 35 | def build_tree(self, s, e): 36 | """ 37 | segment: [s, e) 38 | """ 39 | if s >= e: 40 | return None 41 | 42 | if s+1 == e: 43 | return Node(s, e, self.A[s]) 44 | 45 | left = self.build_tree(s, (s+e)/2) 46 | right = self.build_tree((s+e)/2, e) 47 | val = DEFAULT 48 | if left: val = f(val, left.m) 49 | if right: val = f(val, right.m) 50 | root = Node(s, e, val) 51 | root.left = left 52 | root.right = right 53 | 54 | return root 55 | 56 | def query(self, root, s, e): 57 | """ 58 | :type root: Node 59 | """ 60 | if not root: 61 | return DEFAULT 62 | 63 | if s <= root.start and e >= root.end: 64 | return root.m 65 | 66 | if s >= root.end or e <= root.start: 67 | return DEFAULT 68 | 69 | l = self.query(root.left, s, e) 70 | r = self.query(root.right, s, e) 71 | return f(l, r) 72 | 73 | 74 | class Solution: 75 | def intervalMinNumber(self, A, queries): 76 | """ 77 | Interval Tree 78 | 79 | :param A: integer array 80 | :param queries: The ith query is [queries[i-1].start, queries[i-1].end] 81 | :return: The result list 82 | """ 83 | ret = [] 84 | tree = SegmentTree(A) 85 | for q in queries: 86 | ret.append(tree.query(tree.root, q.start, q.end+1)) 87 | 88 | return ret -------------------------------------------------------------------------------- /Interval Sum II.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array in the construct method, implement two methods query(start, end) and modify(index, value): 3 | 4 | For query(start, end), return the sum from index start to index end in the given array. 5 | For modify(index, value), modify the number in the given index to value 6 | Have you met this question in a real interview? Yes 7 | Example 8 | Given array A = [1,2,7,8,5]. 9 | 10 | query(0, 2), return 10. 11 | modify(0, 4), change A[0] from 1 to 4. 12 | query(0, 1), return 6. 13 | modify(2, 1), change A[2] from 7 to 1. 14 | query(2, 4), return 14. 15 | Note 16 | We suggest you finish problem Segment Tree Build, Segment Tree Query and Segment Tree Modify first. 17 | 18 | Challenge 19 | O(logN) time for query and modify. 20 | """ 21 | __author__ = 'Daniel' 22 | DEFAULT = 0 23 | f = lambda x, y: x+y 24 | 25 | 26 | class Node(object): 27 | def __init__(self, start, end, m): 28 | self.start, self.end, self.m = start, end, m 29 | self.left, self.right = None, None 30 | 31 | 32 | class SegmentTree(object): 33 | def __init__(self, A): 34 | self.A = A 35 | self.root = self.build_tree(0, len(self.A)) 36 | 37 | def build_tree(self, s, e): 38 | """ 39 | segment: [s, e) 40 | """ 41 | if s >= e: 42 | return None 43 | 44 | if s+1 == e: 45 | return Node(s, e, self.A[s]) 46 | 47 | left = self.build_tree(s, (s+e)/2) 48 | right = self.build_tree((s+e)/2, e) 49 | val = DEFAULT 50 | if left: val = f(val, left.m) 51 | if right: val = f(val, right.m) 52 | root = Node(s, e, val) 53 | root.left = left 54 | root.right = right 55 | 56 | return root 57 | 58 | def query(self, root, s, e): 59 | """ 60 | :type root: Node 61 | """ 62 | if not root: 63 | return DEFAULT 64 | 65 | if s <= root.start and e >= root.end: 66 | return root.m 67 | 68 | if s >= root.end or e <= root.start: 69 | return DEFAULT 70 | 71 | l = self.query(root.left, s, e) 72 | r = self.query(root.right, s, e) 73 | return f(l, r) 74 | 75 | def modify(self, root, idx, val): 76 | """ 77 | :type root: Node 78 | """ 79 | if not root or idx >= root.end or idx < root.start: 80 | return 81 | 82 | if idx == root.start and idx == root.end-1: 83 | root.m = val 84 | self.A[idx] = val 85 | return 86 | 87 | self.modify(root.left, idx, val) 88 | self.modify(root.right, idx, val) 89 | val = DEFAULT 90 | if root.left: val = f(val, root.left.m) 91 | if root.right: val = f(val, root.right.m) 92 | root.m = val 93 | 94 | 95 | class Solution: 96 | def __init__(self, A): 97 | """ 98 | :param A: An integer list 99 | :return: None 100 | """ 101 | self.tree = SegmentTree(A) 102 | 103 | def query(self, start, end): 104 | """ 105 | :param start, end: Indices 106 | :return: The sum from start to end 107 | """ 108 | return self.tree.query(self.tree.root, start, end+1) 109 | 110 | def modify(self, index, value): 111 | """ 112 | modify A[index] to value. 113 | """ 114 | self.tree.modify(self.tree.root, index, value) 115 | -------------------------------------------------------------------------------- /Interval Sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array (index from 0 to n-1, where n is the size of this array), and an query list. Each query has two 3 | integers [start, end]. For each query, calculate the sum number between index start and end in the given array, return 4 | the result list. 5 | 6 | Example 7 | For array [1,2,7,8,5], and queries [(1,2),(0,4),(2,4)], return [9,23,20] 8 | 9 | Note 10 | We suggest you finish problem Segment Tree Build, Segment Tree Query and Segment Tree Modify first. 11 | 12 | Challenge 13 | O(logN) time for each query 14 | """ 15 | DEFAULT = 0 16 | f = lambda x, y: x+y 17 | 18 | 19 | class Node(object): 20 | def __init__(self, start, end, m): 21 | self.start, self.end, self.m = start, end, m 22 | self.left, self.right = None, None 23 | 24 | 25 | class SegmentTree(object): 26 | def __init__(self, A): 27 | self.A = A 28 | self.root = self.build_tree(0, len(self.A)) 29 | 30 | def build_tree(self, s, e): 31 | """ 32 | segment: [s, e) 33 | """ 34 | if s >= e: 35 | return None 36 | 37 | if s+1 == e: 38 | return Node(s, e, self.A[s]) 39 | 40 | left = self.build_tree(s, (s+e)/2) 41 | right = self.build_tree((s+e)/2, e) 42 | val = DEFAULT 43 | if left: val = f(val, left.m) 44 | if right: val = f(val, right.m) 45 | root = Node(s, e, val) 46 | root.left = left 47 | root.right = right 48 | 49 | return root 50 | 51 | def query(self, root, s, e): 52 | """ 53 | :type root: Node 54 | """ 55 | if not root: 56 | return DEFAULT 57 | 58 | if s <= root.start and e >= root.end: 59 | return root.m 60 | 61 | if s >= root.end or e <= root.start: 62 | return DEFAULT 63 | 64 | l = self.query(root.left, s, e) 65 | r = self.query(root.right, s, e) 66 | return f(l, r) 67 | 68 | 69 | class Solution: 70 | def intervalSum(self, A, queries): 71 | """ 72 | Interval Tree 73 | 74 | Alternative method: dp 75 | :param A: integer array 76 | :param queries: The ith query is [queries[i-1].start, queries[i-1].end] 77 | :return: The result list 78 | """ 79 | ret = [] 80 | tree = SegmentTree(A) 81 | for q in queries: 82 | ret.append(tree.query(tree.root, q.start, q.end+1)) 83 | 84 | return ret 85 | 86 | 87 | -------------------------------------------------------------------------------- /Kth Largest Element.py: -------------------------------------------------------------------------------- 1 | """ 2 | Find K-th largest element in an array. 3 | Note 4 | 5 | You can swap elements in the array 6 | Example 7 | 8 | In array [9,3,2,4,8], the 3th largest element is 4 9 | Challenge 10 | 11 | O(n) time, O(1) space 12 | """ 13 | __author__ = 'Danyang' 14 | 15 | 16 | class Solution: 17 | def kthLargestElement(self, k, A): 18 | """ 19 | partial quick sort 20 | 21 | :param k: int 22 | :param A: lst 23 | :return: int 24 | """ 25 | k = len(A)-k 26 | return self.find_kth(A, 0, len(A), k) 27 | 28 | def find_kth(self, A, i, j, k): 29 | p = self.pivot_optimized(A, i, j) 30 | if k == p: 31 | return A[p] 32 | elif k < p: 33 | return self.find_kth(A, i, p, k) 34 | else: 35 | return self.find_kth(A, p+1, j, k) 36 | 37 | def pivot(self, A, i, j): 38 | p = i 39 | closed = p 40 | for ptr in xrange(i, j): 41 | if A[ptr] < A[p]: 42 | closed += 1 43 | A[closed], A[ptr] = A[ptr], A[closed] 44 | 45 | A[closed], A[p] = A[p], A[closed] 46 | return closed 47 | 48 | def pivot_optimized(self, A, lo, hi): 49 | """ 50 | Fix the pivot as the 1st element 51 | Scan from left to right and right to left simultaneously 52 | Avoid the case that the algo goes O(N^2) with duplicate keys 53 | """ 54 | i = lo 55 | j = hi 56 | while True: 57 | while True: 58 | i += 1 59 | if i >= hi or A[i] >= A[lo]: 60 | break 61 | while True: 62 | j -= 1 63 | if j < lo or A[j] <= A[lo]: 64 | break 65 | 66 | if i >= j: 67 | break 68 | 69 | A[i], A[j] = A[j], A[i] 70 | 71 | A[lo], A[j] = A[j], A[lo] 72 | return j 73 | 74 | def pivot_3way(self, A, lo, hi): 75 | lt = lo-1 # pointing to end of array LT 76 | gt = hi # pointing to the end of array GT (reversed) 77 | 78 | v = A[lo] 79 | i = lo # scanning pointer 80 | while i < gt: 81 | if A[i] < v: 82 | lt += 1 83 | A[lt], A[i] = A[i], A[lt] 84 | i += 1 85 | elif A[i] > v: 86 | gt -= 1 87 | A[gt], A[i] = A[i], A[gt] 88 | else: 89 | i += 1 90 | 91 | return lt+1, gt 92 | 93 | 94 | if __name__ == "__main__": 95 | assert Solution().kthLargestElement(10, range(1, 11)) == 1 96 | 97 | -------------------------------------------------------------------------------- /Kth Prime Number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Design an algorithm to find the kth number such that the only prime factors are 3, 5, and 7. 3 | 4 | The eligible numbers are like 3, 5, 7, 9, 15 ... 5 | Example 6 | 7 | If k=4, return 9. 8 | Challenge 9 | 10 | O(n log n) or O(n) time 11 | """ 12 | __author__ = 'Danyang' 13 | 14 | 15 | class QueueNode(object): 16 | def __init__(self, val): 17 | self.val = val 18 | self.q = [val] # queue, self.q = None 19 | 20 | def __cmp__(self, other): 21 | return self.val-other.val 22 | 23 | def __repr__(self): 24 | return repr(self.val) 25 | 26 | def next(self): 27 | self.q.pop(0) 28 | self.val = self.q[0] 29 | 30 | 31 | class Solution: 32 | def kthPrimeNumber(self, k): 33 | """ 34 | heap and queue 35 | 36 | :param k: 37 | :return: 38 | """ 39 | import heapq 40 | 41 | h1 = QueueNode(3) 42 | h2 = QueueNode(5) 43 | h3 = QueueNode(7) 44 | 45 | heap = [h1, h2, h3] 46 | heapq.heapify(heap) 47 | 48 | for cnt in xrange(k-1): 49 | h = heapq.heappop(heap) 50 | if h == h1: 51 | h1.q.append(h1.val*3) 52 | h2.q.append(h1.val*5) 53 | h3.q.append(h1.val*7) 54 | elif h == h2: 55 | h2.q.append(h2.val*5) 56 | h3.q.append(h2.val*7) 57 | else: 58 | h3.q.append(h3.val*7) 59 | 60 | h.next() 61 | heapq.heappush(heap, h) 62 | 63 | return heapq.heappop(heap).val 64 | 65 | def kthPrimeNumber_error(self, k): 66 | """ 67 | heap and queue 68 | 69 | Erroneous on re-appending the next items on the same queue 70 | Example of errors: 45 is repeated, 45 = 3*3*5 and 45 = 3*5*3 71 | 72 | :param k: 73 | :return: 74 | """ 75 | import heapq 76 | 77 | h1 = QueueNode(3) 78 | h2 = QueueNode(5) 79 | h3 = QueueNode(7) 80 | 81 | heap = [h1, h2, h3] 82 | heapq.heapify(heap) 83 | 84 | for cnt in xrange(k-1): 85 | h = heapq.heappop(heap) 86 | if h == h1: 87 | for i in [3, 5, 7]: 88 | h1.q.append(i*h1.val) 89 | 90 | h1.next() 91 | heapq.heappush(heap, h1) 92 | elif h == h2: 93 | for i in [5, 7]: 94 | h2.q.append(i*h2.val) 95 | 96 | h2.next() 97 | heapq.heappush(heap, h2) 98 | else: 99 | for i in [7]: 100 | h3.q.append(i*h3.val) 101 | 102 | h3.next() 103 | heapq.heappush(heap, h3) 104 | 105 | return heapq.heappop(heap).val 106 | 107 | 108 | if __name__ == "__main__": 109 | assert Solution().kthPrimeNumber(321) == 14586075 -------------------------------------------------------------------------------- /LRU Cache.py: -------------------------------------------------------------------------------- 1 | """ 2 | esign and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: 3 | get and set. 4 | 5 | get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. 6 | set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it 7 | should invalidate the least recently used item before inserting a new item. 8 | """ 9 | __author__ = 'Daniel' 10 | 11 | 12 | class Node(object): 13 | def __init__(self, key, val): 14 | self.key = key 15 | self.val = val 16 | self.pre, self.next = None, None 17 | 18 | 19 | class LRUCache(object): 20 | def __init__(self, capacity): 21 | self.cap = capacity 22 | self.map = {} # key to node 23 | self.head = None 24 | self.tail = None 25 | 26 | def get(self, key): 27 | if key in self.map: 28 | cur = self.map[key] 29 | self._elevate(cur) 30 | return cur.val 31 | 32 | return -1 33 | 34 | def set(self, key, value): 35 | if key in self.map: 36 | cur = self.map[key] 37 | cur.val = value 38 | self._elevate(cur) 39 | else: 40 | cur = Node(key, value) 41 | self.map[key] = cur 42 | self._appendleft(cur) 43 | 44 | if len(self.map) > self.cap: 45 | last = self._pop() 46 | del self.map[last.key] 47 | 48 | # doubly linked-list operations only 49 | def _appendleft(self, cur): 50 | """Normal or initially empty""" 51 | if not self.head and not self.tail: 52 | self.head = cur 53 | self.tail = cur 54 | return 55 | 56 | head = self.head 57 | cur.next, cur.pre, head.pre = head, None, cur 58 | self.head = cur 59 | 60 | def _pop(self): 61 | """Normal or resulting empty""" 62 | last = self.tail 63 | if self.head == self.tail: 64 | self.head, self.tail = None, None 65 | return last 66 | 67 | pre = last.pre 68 | pre.next = None 69 | self.tail = pre 70 | return last 71 | 72 | def _elevate(self, cur): 73 | """Head, Tail, Middle""" 74 | pre, nxt = cur.pre, cur.next 75 | if not pre: 76 | return 77 | elif not nxt: 78 | assert self.tail == cur 79 | self._pop() 80 | else: 81 | pre.next, nxt.pre = nxt, pre 82 | 83 | self._appendleft(cur) 84 | -------------------------------------------------------------------------------- /Largest Number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a list of non negative integers, arrange them such that they form the largest number. 3 | 4 | Example 5 | Given [1, 20, 23, 4, 8], the largest formed number is 8423201. 6 | """ 7 | __author__ = 'Daniel' 8 | 9 | 10 | class Solution: 11 | def largestNumber(self, nums): 12 | """ 13 | Start off by enumerate simple examples 14 | 15 | Compare digit by digit 16 | The comparator is the core. 17 | 18 | :type nums: list[int] 19 | :rtype: str 20 | """ 21 | nums = map(str, nums) 22 | nums.sort(cmp=self.cmp, reverse=True) 23 | nums = "".join(nums) 24 | nums = nums.lstrip("0") 25 | if not nums: 26 | nums = "0" 27 | return nums 28 | 29 | def cmp(self, a, b): 30 | """ 31 | :type a: str 32 | :type b: str 33 | :rtype: int 34 | """ 35 | order = 1 36 | if len(a) > len(b): 37 | order = -1 38 | a, b = b, a 39 | 40 | for i in xrange(len(a)): 41 | if int(a[i]) != int(b[i]): 42 | return order*(int(a[i])-int(b[i])) 43 | 44 | if len(a) == len(b): 45 | return 0 46 | 47 | return order*self.cmp(a, b[len(a):]) 48 | 49 | 50 | if __name__ == "__main__": 51 | assert Solution().largestNumber([0, 0]) == "0" 52 | assert Solution().largestNumber([1, 20, 23, 4, 8]) == "8423201" -------------------------------------------------------------------------------- /Longest Common Subsequence.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two strings, find the longest comment subsequence (LCS). 3 | 4 | Your code should return the length of LCS. 5 | """ 6 | __author__ = 'Danyang' 7 | 8 | 9 | class Solution: 10 | def longestCommonSubsequence(self, A, B): 11 | """ 12 | let f(i, j) represents the LCS END WITH A[i], B[j] 13 | f(i, j) = f(i-1, j-1)+1, if A[i] == A[j] 14 | f(i, j) = max{f(i-1, j), f(i, j-1)}, otherwise 15 | 16 | :param A: str 17 | :param B: str 18 | :return: The length of longest common subsequence of A and B. 19 | """ 20 | m = len(A) 21 | n = len(B) 22 | f = [[0 for _ in xrange(n+1)] for _ in xrange(m+1)] 23 | 24 | if m == 0 or n == 0: 25 | return 0 26 | 27 | for i in xrange(1, m+1): 28 | for j in xrange(1, n+1): 29 | if A[i-1] == B[j-1]: 30 | f[i][j] = f[i-1][j-1]+1 31 | else: 32 | f[i][j] = max(f[i][j-1], f[i-1][j]) 33 | 34 | return f[-1][-1] -------------------------------------------------------------------------------- /Longest Common Substring.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two strings, find the longest common substring. 3 | 4 | Return the length of it. 5 | """ 6 | __author__ = 'Danyang' 7 | 8 | 9 | class Solution: 10 | def longestCommonSubstring(self, A, B): 11 | """ 12 | let f(i, j) represents the LCS END WITH A[i], B[j] 13 | f(i, j) = f(i-1, j-1)+1 if A[i] == B[j] 14 | f(i, j) = 0 otherwise 15 | 16 | notice: 17 | * return the maxa rather than f[-1] 18 | 19 | Compared to LC Subsequence, LC Substring: 20 | * f(i, j) second dp function is different 21 | * return the global maximum length rather than the last one. 22 | 23 | :param A: str 24 | :param B: str 25 | :return: the length of the longest common substring. 26 | """ 27 | m = len(A) 28 | n = len(B) 29 | f = [[0 for _ in xrange(n+1)] for _ in xrange(m+1)] 30 | 31 | if m == 0 or n == 0: 32 | return 0 33 | 34 | maxa = -1 35 | for i in xrange(1, m+1): 36 | for j in xrange(1, n+1): 37 | if A[i-1] == B[j-1]: 38 | f[i][j] = f[i-1][j-1]+1 39 | else: 40 | f[i][j] = 0 41 | maxa = max(maxa, f[i][j]) 42 | 43 | return maxa # rather than f[-1][-1] 44 | -------------------------------------------------------------------------------- /Longest Increasing Continuous subsequence.py: -------------------------------------------------------------------------------- 1 | """ 2 | Give you an integer array (index from 0 to n-1, where n is the size of this array), find the longest increasing 3 | continuous subsequence in this array. (The definition of the longest increasing continuous subsequence here can be from 4 | right to left or from left to right) 5 | 6 | Example 7 | For [5, 4, 2, 1, 3], the LICS is [5, 4, 2, 1], return 4. 8 | 9 | For [5, 1, 2, 3, 4], the LICS is [1, 2, 3, 4], return 4. 10 | 11 | Note 12 | O(n) time and O(1) extra space. 13 | """ 14 | __author__ = 'Daniel' 15 | 16 | 17 | class Solution: 18 | def longestIncreasingContinuousSubsequence(self, A): 19 | """ 20 | Trivial 21 | :rtype: int 22 | """ 23 | n = len(A) 24 | if n < 1: 25 | return 0 26 | 27 | maxa = 1 28 | cur = 1 29 | for i in xrange(1, n): # from left 30 | if A[i] > A[i-1]: 31 | cur += 1 32 | maxa = max(maxa, cur) 33 | else: 34 | cur = 1 35 | 36 | cur = 1 37 | for i in xrange(1, n): # from right 38 | if A[n-1-i] > A[n-1-i+1]: 39 | cur += 1 40 | maxa = max(maxa, cur) 41 | else: 42 | cur = 1 43 | 44 | return maxa 45 | -------------------------------------------------------------------------------- /Longest Increasing Subsequence.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a sequence of integers, find the longest increasing subsequence (LIS). 3 | 4 | You code should return the length of the LIS. 5 | """ 6 | __author__ = 'Danyang' 7 | 8 | 9 | class Solution: 10 | def longestIncreasingSubsequence(self, nums): 11 | """ 12 | let f(i) be the LIS END WITH A[i] 13 | f(i) = max(f(j)+1) if A[i]>=A[j] \forall j, j= nums[j]: 31 | f[i] = max(f[i], f[j]+1) 32 | 33 | maxa = max(maxa, f[i]) 34 | 35 | return maxa # rather than f[-1] 36 | 37 | 38 | if __name__ == "__main__": 39 | assert Solution().longestIncreasingSubsequence( 40 | [88, 4, 24, 82, 86, 1, 56, 74, 71, 9, 8, 18, 26, 53, 77, 87, 60, 27, 69, 17, 76, 23, 67, 14, 98, 13, 10, 83, 20, 41 | 43, 39, 29, 92, 31, 0, 30, 90, 70, 37, 59]) == 10 -------------------------------------------------------------------------------- /Longest Palindromic Substring.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, 3 | and there exists one unique longest palindromic substring. 4 | 5 | Example 6 | Given the string = "abcdzdcab", return "cdzdc". 7 | 8 | Challenge 9 | O(n^2) time is acceptable. Can you do it in O(n) time. 10 | """ 11 | __author__ = 'Daniel' 12 | 13 | 14 | class Solution: 15 | def longestPalindrome(self, s): 16 | """ 17 | O(n) Manacer's algorithm 18 | 19 | O(n^2) dp 20 | :param s: 21 | :return: 22 | """ 23 | n = len(s) 24 | pa = [[False for _ in xrange(n+1)] for _ in xrange(n)] 25 | for i in xrange(n): 26 | pa[i][i] = True 27 | pa[i][i+1] = True 28 | 29 | maxa = (0, 1) 30 | for i in xrange(n-2, -1, -1): 31 | for j in xrange(i+2, n+1): 32 | pa[i][j] = pa[i+1][j-1] and s[i] == s[j-1] 33 | if pa[i][j] and j-i > maxa[1]-maxa[0]: 34 | maxa = (i, j) 35 | 36 | return s[maxa[0]:maxa[1]] 37 | 38 | 39 | if __name__ == "__main__": 40 | assert Solution().longestPalindrome("abcdzdcab") == "cdzdc" 41 | -------------------------------------------------------------------------------- /Longest Substring Without Repeating Characters.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string, find the length of the longest substring without repeating characters. 3 | 4 | Example 5 | For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. 6 | 7 | For "bbbbb" the longest substring is "b", with the length of 1. 8 | 9 | Challenge 10 | O(n) time 11 | """ 12 | __author__ = 'Daniel' 13 | 14 | 15 | class Solution: 16 | def lengthOfLongestSubstring(self, s): 17 | b = 0 18 | e = 0 19 | n = len(s) 20 | maxa = 0 21 | st = set() # window 22 | while e < n: 23 | while s[e] in st: 24 | st.remove(s[b]) 25 | b += 1 26 | 27 | st.add(s[e]) 28 | e += 1 29 | maxa = max(maxa, e-b) 30 | 31 | return maxa 32 | 33 | if __name__ == "__main__": 34 | assert Solution().lengthOfLongestSubstring("abcabcbb") == 3 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Longest Substring with At Most K Distinct Characters.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string s, find the length of the longest substring T that contains at most k distinct characters. 3 | 4 | Example 5 | For example, Given s = "eceba", k = 3, 6 | 7 | T is "eceb" which its length is 4. 8 | 9 | Challenge 10 | O(n), n is the size of the string s. 11 | """ 12 | __author__ = 'Daniel' 13 | 14 | 15 | class Solution: 16 | def lengthOfLongestSubstringKDistinct(self, s, k): 17 | """ 18 | Sliding window 19 | :param s: A string 20 | :param k: An integer 21 | :return: 22 | """ 23 | if len(s)<1 or k<1: 24 | return 0 25 | 26 | cnt = {} 27 | b = 0 28 | e = 1 29 | cnt[s[b]] = 1 30 | maxa = 1 31 | while ek: 40 | cnt[s[b]] -= 1 41 | if cnt[s[b]]<=0: 42 | del cnt[s[b]] 43 | b += 1 44 | 45 | maxa = max(maxa, e-b) 46 | 47 | return maxa 48 | 49 | if __name__=="__main__": 50 | assert Solution().lengthOfLongestSubstringKDistinct("eceba", 3)==4 51 | -------------------------------------------------------------------------------- /Longest Words.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a dictionary, find all of the longest words in the dictionary. 3 | 4 | Have you met this question in a real interview? Yes 5 | Example 6 | Given 7 | 8 | { 9 | "dog", 10 | "google", 11 | "facebook", 12 | "internationalization", 13 | "blabla" 14 | } 15 | the longest words are(is) ["internationalization"]. 16 | 17 | Given 18 | 19 | { 20 | "like", 21 | "love", 22 | "hate", 23 | "yes" 24 | } 25 | the longest words are ["like", "love", "hate"]. 26 | """ 27 | __author__ = 'Daniel' 28 | 29 | 30 | class Solution: 31 | def longestWords(self, dictionary): 32 | """ 33 | 34 | :param dictionary: a list of strings 35 | :return: a list of strings 36 | """ 37 | ret = [] 38 | for word in dictionary: 39 | if not ret or len(word) > len(ret[0]): 40 | ret = [word] 41 | 42 | elif len(word) == len(ret[0]): 43 | ret.append(word) 44 | 45 | return ret 46 | -------------------------------------------------------------------------------- /Lowest Common Ancestor.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given the root and two nodes in a Binary Tree. Find the lowest common ancestor(LCA) of the two nodes. 3 | 4 | The lowest common ancestor is the node with largest depth which is the ancestor of both nodes. 5 | 6 | Example 7 | 4 8 | 9 | / \ 10 | 11 | 3 7 12 | 13 | / \ 14 | 15 | 5 6 16 | 17 | For 3 and 5, the LCA is 4. 18 | 19 | For 5 and 6, the LCA is 7. 20 | 21 | For 6 and 7, the LCA is 7. 22 | """ 23 | __author__ = 'Danyang' 24 | 25 | 26 | class TreeNode: 27 | def __init__(self, val): 28 | self.val = val 29 | self.left, self.right = None, None 30 | 31 | def __repr__(self): 32 | return repr(self.val) 33 | 34 | 35 | class Solution: 36 | def lowestCommonAncestor(self, root, A, B): 37 | """ 38 | O(n) for find path 39 | 40 | ...>LCA***>A 41 | ...>LCA####>B 42 | Any node on two paths before LCA are equal respectively 43 | Any node on two paths after LCA are different respectively 44 | 45 | 1. get the paths from root to A and from root to B 46 | 2. cut longer path's tail to make two equal length 47 | 3. scan backward to find the first common ancestor 48 | 49 | :type root: TreeNode 50 | :type A: TreeNode 51 | :type B: TreeNode 52 | :param root: The root of the binary search tree. 53 | :param A: node in a Binary. 54 | :param B: node 55 | :return: Return the least common ancestor(LCA) of the two nodes. 56 | """ 57 | p1 = self.path(root, A) 58 | p2 = self.path(root, B) 59 | p1.append(TreeNode(0)) # dummy 60 | p2.append(TreeNode(0)) # dummy 61 | for ind, val in enumerate(p1): 62 | if val != p2[ind]: 63 | return p1[ind-1] 64 | 65 | def path(self, root, target): 66 | """ 67 | path from root to target 68 | 69 | :param target: 70 | :return: 71 | """ 72 | ans = [] 73 | self.get_path(root, target, [], ans) 74 | return ans 75 | 76 | def get_path(self, cur, target, path, ans): 77 | """ 78 | 79 | :param cur: 80 | :param target: 81 | :param path: 82 | :param ans: 83 | :return: bool 84 | """ 85 | if not cur: 86 | return False 87 | 88 | path.append(cur) 89 | 90 | if cur == target: # compare by reference 91 | # ans = path 92 | ans.extend(path) # otherwise lose reference 93 | return True 94 | 95 | if cur.left and self.get_path(cur.left, target, path, ans): 96 | return True 97 | 98 | if cur.right and self.get_path(cur.right, target, path, ans): 99 | return True 100 | 101 | path.pop() 102 | return False 103 | 104 | 105 | if __name__ == "__main__": 106 | node = TreeNode(1) 107 | print Solution().lowestCommonAncestor(node, node, node) 108 | 109 | nodes = dict(zip(range(3, 8), [TreeNode(i) for i in range(3, 8)])) 110 | nodes[4].left = nodes[3] 111 | nodes[4].right = nodes[7] 112 | nodes[7].left = nodes[5] 113 | nodes[7].right = nodes[6] 114 | print Solution().lowestCommonAncestor(nodes[4], nodes[3], nodes[5]) 115 | -------------------------------------------------------------------------------- /Majority Number II.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers, the majority number is the number that occurs more than 1/3 of the size of the array. 3 | 4 | Find it. 5 | 6 | Note 7 | There is only one majority number in the array 8 | 9 | Example 10 | For [1, 2, 1, 2, 1, 3, 3] return 1 11 | 12 | Challenge 13 | O(n) time and O(1) space 14 | """ 15 | __author__ = 'Danyang' 16 | 17 | 18 | class Solution: 19 | def majorityNumber(self, nums): 20 | """ 21 | Voting Algorithm 22 | Since majority number must occur more than 1/3, there are at most 2 majority number 23 | 24 | reference: http://www.cnblogs.com/yuzhangcmu/p/4175779.html 25 | 26 | :param nums: 27 | :return: 28 | """ 29 | n1, n2 = None, None 30 | cnt1, cnt2 = 0, 0 31 | 32 | for num in nums: 33 | if num in (n1, n2): 34 | if num == n1: 35 | cnt1 += 1 36 | else: 37 | cnt2 += 1 38 | else: # every time --, discard 3 different numbers 39 | if cnt1 == 0: 40 | n1 = num 41 | cnt1 += 1 42 | elif cnt2 == 0: 43 | n2 = num 44 | cnt2 += 1 45 | else: 46 | cnt1 -= 1 47 | cnt2 -= 1 48 | 49 | # double check 50 | if len(filter(lambda x: x == n1, nums)) > len(nums)/3: 51 | return n1 52 | else: 53 | return n2 54 | 55 | 56 | if __name__ == "__main__": 57 | assert Solution().majorityNumber( 58 | [169, 43, 133, 93, 60, 29, 60, 104, 26, 60, 38, 52, 60, 118, 45, 183, 49, 42, 60, 0, 66, 67, 194, 127, 60, 60, 59 | 60, 60, 60, 60]) == 60 -------------------------------------------------------------------------------- /Majority Number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers, the majority number is the number that occurs more than half of the size of the array. Find 3 | it. 4 | 5 | Example 6 | For [1, 1, 1, 1, 2, 2, 2], return 1 7 | 8 | Challenge 9 | O(n) time and O(1) space 10 | """ 11 | __author__ = 'Danyang' 12 | 13 | 14 | class Solution: 15 | def majorityNumber(self, nums): 16 | """ 17 | Moore's Voting Algorithm 18 | 19 | greedy half 20 | 21 | :param nums: A list of integers 22 | :return: The majority number 23 | """ 24 | cnt = 0 25 | maj = 0 26 | for ind, num in enumerate(nums): 27 | if num == nums[maj]: 28 | cnt += 1 29 | else: 30 | cnt -= 1 # every time --, discard 2 different numbers 31 | 32 | if cnt < 0: 33 | maj = ind 34 | cnt = 1 35 | 36 | # assured that the majority exists, otherwise need to double check 37 | return nums[maj] 38 | 39 | 40 | if __name__ == "__main__": 41 | assert Solution().majorityNumber([1, 1, 1, 2, 2, 2, 2, 1, 1]) == 1 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Matrix Zigzag Traversal.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in ZigZag-order 3 | 4 | Example 5 | Given a matrix: 6 | 7 | [ 8 | [1, 2, 3, 4], 9 | [5, 6, 7, 8], 10 | [9,10, 11, 12] 11 | ] 12 | return [1, 2, 5, 9, 6, 3, 4, 7, 10, 11, 8, 12] 13 | """ 14 | __author__ = 'Daniel' 15 | 16 | 17 | class Solution: 18 | def printZMatrix(self, matrix): 19 | """ 20 | 21 | :param matrix: a matrix of integers 22 | :return: a list of integers 23 | """ 24 | i = 0 25 | j = 0 26 | m = len(matrix) 27 | n = len(matrix[0]) 28 | ret = [] 29 | 30 | up = True 31 | for _ in xrange(m*n): 32 | ret.append(matrix[i][j]) 33 | if up: 34 | if i-1<0 or j+1>=n: 35 | up = False 36 | if j+1>=n: # go down 37 | i += 1 38 | else: # go right 39 | j += 1 40 | else: 41 | i -= 1 42 | j += 1 43 | else: 44 | if i+1>=m or j-1<0: 45 | up = True 46 | if i+1>=m: 47 | j += 1 # go right 48 | else: 49 | i += 1 # go up 50 | else: 51 | i += 1 52 | j -= 1 53 | 54 | return ret 55 | 56 | if __name__=="__main__": 57 | matrix = [ 58 | [1, 2, 3, 4], 59 | [5, 6, 7, 8], 60 | [9, 10, 11, 12] 61 | ] 62 | print Solution().printZMatrix(matrix) 63 | -------------------------------------------------------------------------------- /Max Tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array with no duplicates. A max tree building on this array is defined as follow: 3 | 4 | The root is the maximum number in the array 5 | The left subtree and right subtree are the max trees of the subarray divided by the root number. 6 | Construct the max tree by the given array. 7 | Example 8 | Given [2, 5, 6, 0, 3, 1], the max tree is 9 | 10 | 6 11 | 12 | / \ 13 | 14 | 5 3 15 | 16 | / / \ 17 | 18 | 2 0 1 19 | 20 | 21 | Challenge 22 | O(n) time complexity 23 | """ 24 | __author__ = 'Danyang' 25 | 26 | 27 | class TreeNode(object): 28 | def __init__(self, val): 29 | self.val = val 30 | self.left, self.right = None, None 31 | 32 | 33 | class Solution(object): 34 | def maxTree(self, A): 35 | """ 36 | Cartesian Tree, Heap-ordered, treap, stack O(n) 37 | http://en.wikipedia.org/wiki/Cartesian_tree 38 | 39 | using stack 40 | 1. construct left tree and maintain the Cartesian tree 41 | 2. connect right tree 42 | O(n) since each node on the tree is pushed and popped out from stack once 43 | 44 | 45 | :param A: Given an integer array with no duplicates. 46 | :return: The root of max tree. 47 | """ 48 | stk = [] 49 | for a in A: 50 | cur = TreeNode(a) 51 | while stk and stk[-1].val <= cur.val: 52 | pre = stk.pop() 53 | pre.right = cur.left 54 | cur.left = pre 55 | 56 | stk.append(cur) 57 | 58 | pre = None 59 | while stk: 60 | cur = stk.pop() 61 | cur.right = pre 62 | pre = cur 63 | 64 | return pre 65 | -------------------------------------------------------------------------------- /Maximal Square.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a 2D binary matrix filled with 0's and 1's, find the largest square containing all 1's and return its area. 3 | 4 | Example 5 | For example, given the following matrix: 6 | 7 | 1 0 1 0 0 8 | 1 0 1 1 1 9 | 1 1 1 1 1 10 | 1 0 0 1 0 11 | Return 4. 12 | """ 13 | __author__ = 'Daniel' 14 | 15 | 16 | class Solution: 17 | def maxSquare(self, matrix): 18 | """ 19 | Algorithm: 20 | O(n^2) 21 | let F_{i, j} represents the max square's length ended at matrix_{i, j} (lower right corner). 22 | F_{i, j} = min{F_{i-1, j}, F_{i, j-1}, F_{i-1, j-1}}+1 // if matrix{i, j} == 1 23 | F_{i, j} = 0 // otherwise 24 | 25 | O(n^3) 26 | sandwich approach 27 | 28 | :param matrix: a matrix of 0 and 1 29 | :return: an integer 30 | """ 31 | M = len(matrix) 32 | N = len(matrix[0]) 33 | F = [[0 for _ in xrange(N+1)] for _ in xrange(M+1)] 34 | 35 | gmax = 0 36 | for i in xrange(1, M+1): 37 | for j in xrange(1, N+1): 38 | if matrix[i-1][j-1] == 1: 39 | F[i][j] = min(F[i-1][j], F[i][j-1], F[i-1][j-1])+1 40 | gmax = max(gmax, F[i][j]) 41 | 42 | return gmax*gmax 43 | 44 | def maxSquare_error(self, matrix): 45 | """ 46 | stack 47 | :param matrix: a matrix of 0 and 1 48 | :return: an integer 49 | """ 50 | M = len(matrix) 51 | N = len(matrix[0]) 52 | h = [[0 for _ in xrange(N+1)] for _ in xrange(M+1)] 53 | for i in xrange(1, M+1): 54 | for j in xrange(1, N+1): 55 | if matrix[i-1][j-1] == 1: 56 | h[i][j] = h[i-1][j]+1 57 | else: 58 | h[i][j] = 0 59 | 60 | ret = 0 61 | for i in xrange(M): 62 | stk = [] # col index, inc_stk 63 | for j in xrange(N): 64 | while stk and h[i+1][stk[-1]+1] >= h[i+1][j+1]: 65 | stk.pop() 66 | idx = -1 67 | if stk: idx = stk[-1] 68 | cur_square = min(j-idx, h[i+1][j+1]) 69 | cur_square *= cur_square 70 | ret = max(ret, cur_square) 71 | stk.append(j) 72 | 73 | return ret 74 | 75 | 76 | if __name__ == "__main__": 77 | assert Solution().maxSquare([[0,1,0,1,1,0],[1,0,1,0,1,1],[1,1,1,1,1,0],[1,1,1,1,1,1],[0,0,1,1,1,0],[1,1,1,0,1,1]] 78 | ) == 9 -------------------------------------------------------------------------------- /Maximum Gap.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Given an unsorted array, find the maximum difference between the successive elements in its sorted form. 4 | 5 | Return 0 if the array contains less than 2 elements. 6 | 7 | Example 8 | Given [1, 9, 2, 5], the sorted form of it is [1, 2, 5, 9], the maximum gap is between 5 and 9 = 4. 9 | 10 | Note 11 | You may assume all elements in the array are non-negative integers and fit in the 32-bit signed integer range. 12 | 13 | Challenge 14 | Sort is easy but will cost O(nlogn) time. Try to solve it in linear time and space. 15 | """ 16 | __author__ = 'Daniel' 17 | import sys 18 | 19 | 20 | class Solution: 21 | def maximumGap(self, nums): 22 | """ 23 | O(n lg n) algorithm is trivial, need to speed up to the next possible complexity, i.e. O(n) 24 | 25 | Bucket (histogram bin) algorithm O(n) 26 | The LOWER bound of gap is (max-min)/(n-1), which can be proved by consider evenly distributed numbers and 27 | non-evenly distributed numbers. 28 | 29 | Cluster the numbers into bins like the histogram 30 | Find the maximum gap by examine the maximum distance between elements in neighboring bins. 31 | 32 | :param nums: a list of integers 33 | :return: the maximum difference 34 | """ 35 | n = len(nums) 36 | if n < 2: 37 | return 0 38 | 39 | gmax = max(nums) 40 | gmin = min(nums) 41 | bin_width = max(1, (gmax-gmin)/(n-1)) # lower bound of the max gap 42 | 43 | bins_max = {} # use hash map instead of array since possible empty bin 44 | bins_min = {} 45 | 46 | for elt in nums: 47 | bin_num = (elt-gmin)/bin_width 48 | bins_min[bin_num] = min(bins_min.get(bin_num, sys.maxint), elt) 49 | bins_max[bin_num] = max(bins_max.get(bin_num, -sys.maxint-1), elt) 50 | 51 | max_gap = -1 52 | pre_bin_max = gmin 53 | for i in xrange((gmax-gmin)/bin_width+1): 54 | if i in bins_min: 55 | max_gap = max(max_gap, bins_min[i]-pre_bin_max) 56 | pre_bin_max = bins_max[i] 57 | 58 | return max_gap 59 | 60 | if __name__ == "__main__": 61 | assert Solution().maximumGap([1, 9, 2, 5]) == 4 -------------------------------------------------------------------------------- /Maximum Product Subarray.py: -------------------------------------------------------------------------------- 1 | """ 2 | Find the contiguous subarray within an array (containing at least one number) which has the largest product. 3 | 4 | Example 5 | For example, given the array [2,3,-2,4], the contiguous subarray [2,3] has the largest product = 6. 6 | """ 7 | __author__ = 'Daniel' 8 | 9 | 10 | class Solution(object): 11 | def maxProduct(self, nums): 12 | if not nums: 13 | return 0 14 | 15 | n = len(nums) 16 | smallest = list(nums) 17 | largest = list(nums) 18 | maxa = nums[0] 19 | for i in xrange(1, n): 20 | v = nums[i] 21 | smallest[i] = min(v, smallest[i-1]*v, largest[i-1]*v) 22 | largest[i] = max(v, smallest[i-1]*v, largest[i-1]*v) 23 | maxa = max(maxa, largest[i]) 24 | 25 | return maxa 26 | 27 | 28 | if __name__ == "__main__": 29 | assert Solution().maxProduct([2, 3, -2, 4]) == 6 -------------------------------------------------------------------------------- /Maximum Subarray Difference.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array with integers. 3 | 4 | Find two non-overlapping subarrays A and B, which |SUM(A) - SUM(B)| is the largest. 5 | 6 | Return the largest difference. 7 | 8 | Note 9 | The subarray should contain at least one number 10 | 11 | Example 12 | For [1, 2, -3, 1], return 6 13 | 14 | Challenge 15 | O(n) time and O(n) space. 16 | """ 17 | __author__ = 'Danyang' 18 | 19 | 20 | class Solution: 21 | def maxDiffSubArrays(self, nums): 22 | """ 23 | Algorithm: dp 24 | Maximum Subarray Difference 25 | <= largest difference, max sum - min sum 26 | <= max subarray sum and min subarray sum 27 | <= because non-overlapping max/min subarray sum on one side, the other on the other side 28 | <= split the array into half 29 | 30 | :param nums: A list of integers 31 | :return: An integer indicate the value of maximum difference between two Subarrays 32 | """ 33 | n = len(nums) 34 | min_left = list(nums) 35 | max_left = list(nums) 36 | min_right = list(nums) 37 | max_right = list(nums) 38 | 39 | 40 | # min subarray 41 | current = 0 42 | for i in xrange(n): 43 | current += nums[i] 44 | if i-1 >= 0: 45 | min_left[i] = min(current, min_left[i-1], min_left[i]) 46 | else: 47 | min_left[i] = min(current, min_left[i]) 48 | 49 | if current > 0: 50 | current = 0 51 | 52 | # max subarray 53 | current = 0 54 | for i in xrange(n): 55 | current += nums[i] 56 | if i-1 >= 0: 57 | max_left[i] = max(current, max_left[i-1], max_left[i]) 58 | else: 59 | max_left[i] = max(current, max_left[i]) 60 | 61 | if current < 0: 62 | current = 0 63 | 64 | current = 0 65 | for i in xrange(n-1, -1, -1): 66 | current += nums[i] 67 | if i+1 <= n-1: 68 | max_right[i] = max(current, max_right[i+1], max_right[i]) 69 | else: 70 | max_right[i] = max(current, max_right[i]) 71 | 72 | if current < 0: 73 | current = 0 74 | 75 | current = 0 76 | for i in xrange(n-1, -1, -1): 77 | current += nums[i] 78 | if i+1 <= n-1: 79 | min_right[i] = min(current, min_right[i+1], min_right[i]) 80 | else: 81 | min_right[i] = min(current, min_right[i]) 82 | 83 | if current > 0: 84 | current = 0 85 | 86 | maxa = 0 87 | for i in xrange(n-1): 88 | maxa = max(maxa, abs(max_left[i]-min_right[i+1]), abs(min_left[i]-max_right[i+1])) 89 | 90 | return maxa 91 | 92 | 93 | if __name__ == "__main__": 94 | print Solution().maxDiffSubArrays([-4, 5, -4, 5, -4, 5, -4, 5, -4, 5, -4, 5, -4, 5, -4, 5, -4, 5, -1000]) 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /Maximum Subarray II.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers, find two non-overlapping subarrays which have the largest sum. 3 | 4 | The number in each subarray should be contiguous. 5 | 6 | Return the largest sum. 7 | 8 | Note 9 | The subarray should contain at least one number 10 | 11 | Example 12 | For given [1, 3, -1, 2, -1, 2], the two subarrays are [1, 3] and [2, -1, 2] or [1, 3, -1, 2] and [2], they both have 13 | the largest sum 7. 14 | 15 | Challenge 16 | Can you do it in time complexity O(n) ? 17 | """ 18 | __author__ = 'Danyang' 19 | 20 | 21 | class Solution: 22 | def maxTwoSubArrays(self, nums): 23 | """ 24 | dp max subarray 25 | 26 | fi for subarry that ends WITH OR BEFORE i 27 | 28 | f1 for forward sweeping 29 | f2 for backward sweeping 30 | :param nums: A list of integers 31 | :return: An integer denotes the sum of max two non-overlapping subarrays 32 | """ 33 | n = len(nums) 34 | 35 | f = [[-1<<31 for _ in xrange(n+1)] for _ in xrange(2)] 36 | 37 | cur = 0 38 | for i in xrange(1, n+1): 39 | cur += nums[i-1] 40 | f[0][i] = max(nums[i-1], f[0][i-1], cur) 41 | if cur < 0: 42 | cur = 0 43 | 44 | cur = 0 45 | for i in xrange(n-1, -1, -1): 46 | cur += nums[i] 47 | f[1][i] = max(nums[i], f[1][i+1], cur) 48 | if cur < 0: 49 | cur = 0 50 | 51 | maxa = -1<<31 52 | for i in xrange(1, n): 53 | maxa = max(maxa, f[0][i]+f[1][i]) 54 | return maxa 55 | 56 | 57 | if __name__ == "__main__": 58 | print Solution().maxTwoSubArrays([1, 3, -1, 2, -1, 2]) 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /Maximum Subarray III.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers and a number k, find k non-overlapping subarrays which have the largest sum. 3 | 4 | The number in each subarray should be contiguous. 5 | 6 | Return the largest sum. 7 | 8 | Note 9 | The subarray should contain at least one number 10 | """ 11 | __author__ = 'Danyang' 12 | 13 | 14 | class Solution: 15 | def maxKSubArrays(self, nums, k): 16 | """ 17 | state dp 18 | 19 | f(i, k): max sum of subproblem ending with i, with k subarrays 20 | g(i, k): max sum of subproblem ending with OR before i, with k subarrays 21 | 22 | f(i, k) = max(g(j-1, k-1)+sum(nums[j..i]), for j) 23 | g(i, k) = max(f(j, k), for j) 24 | 25 | reference: http://meetqun.com/thread-3367-1-1.html 26 | 27 | :param nums: A list of integers 28 | :param k: An integer denote to find k non-overlapping subarrays 29 | :return: An integer denote the sum of max k non-overlapping subarrays 30 | """ 31 | n = len(nums) 32 | f = [[0 for _ in xrange(k+1)] for _ in xrange(n+1)] 33 | g = [[0 for _ in xrange(k+1)] for _ in xrange(n+1)] 34 | 35 | s = [0 for _ in xrange(n+1)] # sum 36 | for i in xrange(1, n+1): 37 | s[i] = s[i-1]+nums[i-1] 38 | 39 | for i in xrange(1, n+1): 40 | for st in xrange(1, k+1): 41 | if st == 1: # dummies nodes does not works well with negative numbers 42 | f[i][st] = max([s[i]-s[j] for j in xrange(i)]) 43 | else: 44 | f[i][st] = max([g[j][st-1]+s[i]-s[j] for j in xrange(i)]) 45 | 46 | g[i][st] = max([f[j][st] for j in xrange(i+1)]) 47 | 48 | maxa = -1<<31 49 | for i in xrange(1, n+1): 50 | maxa = max(maxa, g[i][k]) 51 | return maxa 52 | 53 | 54 | if __name__ == "__main__": 55 | print Solution().maxKSubArrays([1, 2, 3], 1) 56 | print Solution().maxKSubArrays([-1, -2, -3, -100, -1, -50], 2) -------------------------------------------------------------------------------- /Median II.py: -------------------------------------------------------------------------------- 1 | """ 2 | Numbers keep coming, return the median of numbers at every time a new number added. 3 | 4 | Example 5 | For numbers coming list: [1, 2, 3, 4, 5], return [1, 1, 2, 2, 3] 6 | 7 | For numbers coming list: [4, 5, 1, 3, 2, 6, 0], return [4, 4, 4, 3, 3, 3, 3] 8 | 9 | For numbers coming list: [2, 20, 100], return [2, 2, 20] 10 | 11 | Challenge 12 | O(nlogn) time 13 | 14 | Clarification 15 | What's the definition of Median? 16 | 17 | Median is the number that in the middle of a sorted array. If there are n numbers in a sorted array A, the median is 18 | A[(n-1)/2]. 19 | For example, if A=[1,2,3], median is 2. If A=[1,19], median is 1. 20 | """ 21 | __author__ = 'Danyang' 22 | import heapq 23 | 24 | 25 | class DualHeap(object): 26 | def __init__(self): 27 | """ 28 | Dual Heap is great in the case where there is no removal. 29 | 30 | :return: 31 | """ 32 | self.min_h = [] 33 | self.max_h = [] 34 | 35 | def insert(self, num): 36 | if not self.min_h or num > self.min_h[0]: 37 | heapq.heappush(self.min_h, num) 38 | else: 39 | heapq.heappush(self.max_h, -num) 40 | self.balance() 41 | 42 | def balance(self): 43 | l1 = len(self.min_h) 44 | l2 = len(self.max_h) 45 | if l1-l2 > 1: 46 | heapq.heappush(self.max_h, -heapq.heappop(self.min_h)) 47 | self.balance() 48 | elif l2-l1 > 1: 49 | heapq.heappush(self.min_h, -heapq.heappop(self.max_h)) 50 | self.balance() 51 | return 52 | 53 | def get_median(self): 54 | l1 = len(self.min_h) 55 | l2 = len(self.max_h) 56 | m = (l1+l2-1)/2 57 | if m == l2-1: 58 | return -self.max_h[0] 59 | elif m == l2: 60 | return self.min_h[0] 61 | raise Exception("not balanced") 62 | 63 | 64 | class Solution: 65 | def medianII(self, nums): 66 | """ 67 | 68 | :param nums: A list of integers. 69 | :return: The median of numbers 70 | """ 71 | dh = DualHeap() 72 | ret = [] 73 | for num in nums: 74 | dh.insert(num) 75 | ret.append(dh.get_median()) 76 | return ret 77 | 78 | if __name__=="__main__": 79 | assert Solution().medianII([4, 5, 1, 3, 2, 6, 0]) == [4, 4, 4, 3, 3, 3, 3] 80 | 81 | 82 | -------------------------------------------------------------------------------- /Median.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a unsorted array with integers, find the median of it. 3 | 4 | A median is the middle number of the array after it is sorted. 5 | 6 | If there are even numbers in the array, return the N/2-th number after sorted. 7 | 8 | Example 9 | Given [4, 5, 1, 2, 3], return 3 10 | 11 | Given [7, 9, 4, 5], return 5 12 | 13 | Challenge 14 | O(n) time. 15 | """ 16 | __author__ = 'Danyang' 17 | 18 | 19 | class Solution: 20 | def median(self, nums): 21 | """ 22 | O(n), to find k-th number 23 | partial quick sort 24 | 25 | :param nums: A list of integers. 26 | :return: An integer denotes the middle number of the array. 27 | """ 28 | n = len(nums) 29 | return self.find_kth(nums, 0, n, (n-1)/2) 30 | 31 | def find_kth(self, A, i, j, k): 32 | p = self.pivot(A, i, j) 33 | if k == p: 34 | return A[p] 35 | elif k > p: 36 | return self.find_kth(A, p+1, j, k) 37 | else: 38 | return self.find_kth(A, i, p, k) 39 | 40 | def pivot(self, A, i, j): 41 | """ 42 | Fix the pivot as the 1st element 43 | In the end, move the pivot to the end of closed set but still inside the closed set, in order to bisect 44 | 45 | pivoting algorithm: 46 | p | closed set | open set | 47 | | closed set p | open set | 48 | """ 49 | p = i 50 | closed = p 51 | for ptr in xrange(i, j): 52 | if A[ptr] < A[p]: 53 | closed += 1 54 | A[ptr], A[closed] = A[closed], A[ptr] 55 | 56 | A[closed], A[p] = A[p], A[closed] 57 | return closed 58 | 59 | 60 | if __name__ == "__main__": 61 | assert Solution().median([4, 5, 1, 2, 3]) == 3 62 | assert Solution().median([7, 9, 4, 5]) == 5 63 | -------------------------------------------------------------------------------- /Minimum Adjustment Cost.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array, adjust each integers so that the difference of every adjcent integers are not greater than a 3 | given number target. 4 | 5 | If the array before adjustment is A, the array after adjustment is B, you should minimize the sum of |A[i]-B[i]| 6 | 7 | Note 8 | You can assume each number in the array is a positive integer and not greater than 100 9 | 10 | Example 11 | Given [1,4,2,3] and target=1, one of the solutions is [2,3,2,3], the adjustment cost is 2 and it's minimal. Return 2. 12 | """ 13 | __author__ = 'Danyang' 14 | 15 | 16 | class Solution: 17 | def MinAdjustmentCost(self, A, target): 18 | """ 19 | state dp 20 | 21 | f[i][j] = min(f[i-1][k] + |a[i]-j|, for k j-l to j+l) 22 | 23 | comments: similar to Vertibi algorithm (Hidden Markov Model) 24 | 25 | :param A: An integer array. 26 | :param target: An integer. 27 | """ 28 | S = 100 29 | n = len(A) 30 | f = [[1<<31 for _ in xrange(S+1)] for _ in xrange(n+1)] 31 | 32 | for j in xrange(S+1): 33 | f[0][j] = 0 34 | 35 | for i in xrange(1, n+1): 36 | for j in xrange(1, S+1): 37 | for k in xrange(max(1, j-target), min(S, j+target)+1): 38 | f[i][j] = min(f[i][j], f[i-1][k]+abs(A[i-1]-j)) 39 | 40 | mini = 1<<31 41 | for j in xrange(1, S+1): 42 | mini = min(mini, f[n][j]) 43 | 44 | return mini 45 | 46 | 47 | if __name__ == "__main__": 48 | assert Solution().MinAdjustmentCost([12, 3, 7, 4, 5, 13, 2, 8, 4, 7, 6, 5, 7], 2) == 19 49 | 50 | -------------------------------------------------------------------------------- /Minimum Subarray.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers, find the subarray with smallest sum. 3 | 4 | Return the sum of the subarray. 5 | 6 | Note 7 | The subarray should contain at least one integer. 8 | 9 | Example 10 | For [1, -1, -2, 1], return -3 11 | """ 12 | __author__ = 'Danyang' 13 | 14 | 15 | class Solution: 16 | def minSubArray(self, nums): 17 | """ 18 | Greedy, dp 19 | 20 | :param nums: a list of integers 21 | :return: A integer denote the sum of minimum subarray 22 | """ 23 | 24 | mini = min(nums) 25 | current = 0 26 | for a in nums: 27 | current += a 28 | mini = min(mini, current) 29 | if current > 0: 30 | current = 0 31 | 32 | return mini 33 | 34 | 35 | if __name__ == "__main__": 36 | assert Solution().minSubArray([1, -1, -2, 1]) == -3 37 | 38 | 39 | -------------------------------------------------------------------------------- /Number of Airplanes in the Sky.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an interval list which are flying and landing time of the flight. How many airplanes are on the sky at most? 3 | 4 | Example 5 | For interval list [[1,10],[2,3],[5,8],[4,7]], return 3 6 | 7 | Note 8 | If landing and flying happens at the same time, we consider landing should happen at first. 9 | """ 10 | __author__ = 'Daniel' 11 | 12 | 13 | class Interval(object): 14 | def __init__(self, start, end): 15 | self.start = start 16 | self.end = end 17 | 18 | 19 | class Solution: 20 | @staticmethod 21 | def cmp(a, b): 22 | """ 23 | :type a: Interval 24 | :type b: Interval 25 | """ 26 | if a.start != b.start: 27 | return a.start-b.start 28 | else: 29 | return a.end-b.end 30 | 31 | def countOfAirplanes(self, airplanes): 32 | """ 33 | 34 | :param airplanes: a list of Interval 35 | :return: an integer 36 | """ 37 | return self.count_heap(airplanes) 38 | 39 | def count_heap(self, intervals): 40 | """ 41 | Heap 42 | 43 | :param intervals: a list of Interval 44 | :return: an integer 45 | """ 46 | import heapq 47 | 48 | intervals.sort(cmp=Solution.cmp) 49 | heap = [] 50 | cnt = 0 51 | for intv in intervals: 52 | # in, with upper boundary 53 | heapq.heappush(heap, intv.end) 54 | # out, by comparing lower boundary 55 | while heap[0] <= intv.start: 56 | heapq.heappop(heap) 57 | 58 | cnt = max(cnt, len(heap)) 59 | 60 | return cnt 61 | 62 | 63 | if __name__ == "__main__": 64 | assert Solution().countOfAirplanes([Interval(i[0], i[1]) for i in [[1, 10], [2, 3], [5, 8], [4, 7]]]) == 3 -------------------------------------------------------------------------------- /Number of Islands II.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a n,m which means the row and column of the 2D matrix and an array of pair A( size k). Originally, the 2D matrix 3 | is all 0 which means there is only sea in the matrix. The list pair has k operator and each operator has two integer 4 | A[i].x, A[i].y means that you can change the grid matrix[A[i].x][A[i].y] from sea to island. Return how many island are 5 | there in the matrix after each operator. 6 | 7 | Example 8 | Given n = 3, m = 3, array of pair A = [(0,0),(0,1),(2,2),(2,1)]. 9 | 10 | return [1,1,2,2]. 11 | 12 | Note 13 | 0 is represented as the sea, 1 is represented as the island. If two 1 is adjacent, we consider them in the same island. 14 | We only consider up/down/left/right adjacent. 15 | """ 16 | import random 17 | 18 | __author__ = 'Daniel' 19 | 20 | 21 | class Point(object): 22 | def __init__(self, a=0, b=0): 23 | self.x = a 24 | self.y = b 25 | 26 | def __repr__(self): 27 | return "[%d, %d]" % (self.x, self.y) 28 | 29 | 30 | class UnionFind(object): 31 | """ 32 | Weighted Union Find with path compression 33 | """ 34 | 35 | def __init__(self, rows, cols): 36 | # hashing will cause TLE; use direct array access instead 37 | self.pi = [-1 for _ in xrange(rows*cols)] # item -> pi 38 | self.sz = [-1 for _ in xrange(rows*cols)] # root -> size 39 | self.count = 0 40 | 41 | def add(self, item): 42 | if self.pi[item] == -1: 43 | self.pi[item] = item 44 | self.sz[item] = 1 45 | self.count += 1 46 | 47 | def union(self, a, b): 48 | pi1 = self._pi(a) 49 | pi2 = self._pi(b) 50 | 51 | if pi1 != pi2: 52 | if self.sz[pi1] > self.sz[pi2]: 53 | pi1, pi2 = pi2, pi1 54 | 55 | self.pi[pi1] = pi2 56 | self.sz[pi2] += self.sz[pi1] 57 | self.count -= 1 58 | 59 | def _pi(self, item): 60 | pi = self.pi[item] 61 | if item != pi: 62 | self.pi[item] = self._pi(pi) 63 | 64 | return self.pi[item] 65 | 66 | 67 | class Solution: 68 | def __init__(self): 69 | self.dirs = ((-1, 0), (1, 0), (0, -1), (0, 1)) 70 | 71 | def numIslands2(self, n, m, operators): 72 | """ 73 | :type n: int 74 | :type m: int 75 | :type operators: list[Point] 76 | :rtype: list[int] 77 | """ 78 | rows = n 79 | cols = m 80 | unroll = lambda x, y: x*cols+y # hash will be slower 81 | mat = [[0 for _ in xrange(cols)] for _ in xrange(rows)] 82 | uf = UnionFind(rows, cols) 83 | ret = [] 84 | for op in operators: 85 | uf.add(unroll(op.x, op.y)) 86 | mat[op.x][op.y] = 1 87 | for dir in self.dirs: 88 | x1 = op.x+dir[0] 89 | y1 = op.y+dir[1] 90 | if 0 <= x1 < rows and 0 <= y1 < cols and mat[x1][y1] == 1: 91 | uf.union(unroll(op.x, op.y), unroll(x1, y1)) 92 | 93 | ret.append(uf.count) 94 | 95 | return ret 96 | 97 | 98 | class TestCaseGenerator(object): 99 | def _generate(self): 100 | dim = 10 101 | m = random.randrange(1, dim) 102 | n = random.randrange(1, dim) 103 | k = random.randrange(1, max(2, m*n/3)) 104 | operators = [] 105 | visited = set() 106 | while len(operators) < k: 107 | p = random.randrange(m*n) 108 | if p not in visited: 109 | x = p/n 110 | y = p%n 111 | operators.append(Point(x, y)) 112 | visited.add(p) 113 | 114 | print(m) 115 | print(n) 116 | print(operators) 117 | 118 | def generate(self, T=50): 119 | for _ in xrange(T): 120 | self._generate() 121 | 122 | 123 | if __name__ == "__main__": 124 | assert Solution().numIslands2(3, 3, map(lambda x: Point(x[0], x[1]), [(0, 0), (0, 1), (2, 2), (2, 1)])) == [1, 1, 2, 125 | 2] 126 | testcase = TestCaseGenerator() 127 | testcase.generate() 128 | -------------------------------------------------------------------------------- /Number of Islands.py: -------------------------------------------------------------------------------- 1 | """ 2 | Easy Number of Islands 3 | 4 | 19% Accepted 5 | Given a boolean 2D matrix, find the number of islands. 6 | 7 | Have you met this question in a real interview? Yes 8 | Example 9 | Given graph: 10 | 11 | [ 12 | [1, 1, 0, 0, 0], 13 | [0, 1, 0, 0, 1], 14 | [0, 0, 0, 1, 1], 15 | [0, 0, 0, 0, 0], 16 | [0, 0, 0, 0, 1] 17 | ] 18 | return 3. 19 | 20 | Note 21 | 0 is represented as the sea, 1 is represented as the island. If two 1 is adjacent, we consider them in the same island. 22 | We only consider up/down/left/right adjacent. 23 | """ 24 | __author__ = 'Daniel' 25 | 26 | 27 | class Solution: 28 | def __init__(self): 29 | self.dirs = [[0, -1], [0, 1], [1, 0], [-1, 0]] 30 | 31 | def numIslands(self, grid): 32 | """ 33 | 34 | :param grid: {boolean[][]} grid a boolean 2D matrix 35 | :return: {int} an integer 36 | """ 37 | if not grid: return 0 38 | m = len(grid) 39 | if not m: return 0 40 | n = len(grid[0]) 41 | visited = [[False for _ in xrange(n)] for _ in xrange(m)] 42 | cnt = 0 43 | for i in xrange(m): 44 | for j in xrange(n): 45 | if not visited[i][j] and grid[i][j]: 46 | cnt += 1 47 | self.dfs(grid, i, j, visited) 48 | 49 | return cnt 50 | 51 | def dfs(self, grid, i, j, visited): 52 | # pre-call check 53 | m = len(grid) 54 | n = len(grid[0]) 55 | visited[i][j] = True 56 | for dir in self.dirs: 57 | i1 = i+dir[0] 58 | j1 = j+dir[1] 59 | if 0 <= i1 < m and 0 <= j1 < n and not visited[i1][j1] and grid[i1][j1]: 60 | self.dfs(grid, i1, j1, visited) 61 | -------------------------------------------------------------------------------- /Nuts & Bolts Problem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a set of n nuts of different sizes and n bolts of different sizes. There is a one-one mapping between nuts and bolts. Comparison of a nut to another nut or a bolt to another bolt is not allowed. It means nut can only be compared with bolt and bolt can only be compared with nut to see which one is bigger/smaller. 3 | 4 | We will give you a compare function to compare nut with bolt. 5 | 6 | Example 7 | Given nuts = ['ab','bc','dd','gg'], bolts = ['AB','GG', 'DD', 'BC']. 8 | 9 | Your code should find the matching bolts and nuts. 10 | 11 | one of the possible return: 12 | 13 | nuts = ['ab','bc','dd','gg'], bolts = ['AB','BC','DD','GG']. 14 | 15 | The order of the nuts or bolts does not matter. You just need to find the matching bolt for each nut. 16 | """ 17 | __author__ = 'Daniel' 18 | try: 19 | from lintcode import Compare 20 | except ImportError: 21 | class Compare: 22 | @classmethod 23 | def cmp(cls, a, b): 24 | """ 25 | THIS IS A SAMPLE CMP FOR TESTING. 26 | 27 | You can use Compare.cmp(a, b) to compare nuts "a" and bolts "b", 28 | if "a" is bigger than "b", it will return 1, else if they are equal, 29 | it will return 0, else if "a" is smaller than "b", it will return -1. 30 | When "a" is not a nut or "b" is not a bolt, it will return 2, which is not valid. 31 | :param a: 32 | :param b: 33 | :return: 34 | """ 35 | a = a.lower() 36 | b = b.lower() 37 | 38 | diff = ord(a)-ord(b) 39 | if diff < 0: 40 | return -1 41 | elif diff > 0: 42 | return 1 43 | else: 44 | return 0 45 | 46 | 47 | class Solution: 48 | def sortNutsAndBolts(self, nuts, bolts): 49 | """ 50 | :param nuts: a list of nuts 51 | :param bolts: a list of bolts 52 | :return: 53 | """ 54 | assert len(nuts) == len(bolts) 55 | self.quick_sort(nuts, bolts, 0, len(nuts)) 56 | 57 | def quick_sort(self, nuts, bolts, start, end): 58 | """ 59 | Quick sort over two arrays 60 | :param nuts: 61 | :param bolts: 62 | :param start: 63 | :param end: 64 | :return: 65 | """ 66 | if start >= end: 67 | return 68 | 69 | pivot = self.partition(nuts, bolts[start], start, end) 70 | self.partition(bolts, nuts[pivot], start, end) 71 | self.quick_sort(nuts, bolts, start, pivot) 72 | self.quick_sort(nuts, bolts, pivot+1, end) 73 | 74 | def partition(self, A, pivot, start, end): 75 | """ 76 | Use bolt to partition nuts/ Use nut to partition nuts 77 | Bolt and nut are swappable in the parameter 78 | 79 | In-place partition 80 | 81 | :param A: nuts or bolts, the counterpart of pivot 82 | :param pivot: bolt or nut 83 | :param start: 84 | :param end: 85 | :return: pivot 86 | """ 87 | left = start # save for the counterpart's pivot 88 | i = start+1 89 | while i < end: 90 | if Compare.cmp(A[i], pivot) == -1 or Compare.cmp(pivot, A[i]) == 1: 91 | left += 1 92 | A[left], A[i] = A[i], A[left] 93 | i += 1 94 | elif Compare.cmp(A[i], pivot) == 0 or Compare.cmp(pivot, A[i]) == 0: 95 | A[start], A[i] = A[i], A[start] 96 | else: 97 | i += 1 98 | 99 | # move the counterpart's pivot from start to left 100 | A[start], A[left] = A[left], A[start] 101 | 102 | return left 103 | 104 | 105 | if __name__ == "__main__": 106 | nuts = ['a', 'b', 'd', 'g'] 107 | bolts = ['A', 'G', 'D', 'B'] 108 | Solution().sortNutsAndBolts(nuts, bolts) 109 | assert nuts == ['a', 'b', 'd', 'g'] 110 | assert bolts == ['A', 'B', 'D', 'G'] -------------------------------------------------------------------------------- /Palindrome Partitioning.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string s, partition s such that every substring of the partition is a palindrome. 3 | 4 | Return all possible palindrome partitioning of s. 5 | """ 6 | __author__ = 'Daniel' 7 | 8 | 9 | class Solution: 10 | def partition(self, s): 11 | """ 12 | :type s: str 13 | :rtype: List[str] 14 | """ 15 | ret = [] 16 | self.backtrack(s, [], ret) 17 | return ret 18 | 19 | def backtrack(self, s, cur_lvl, ret): 20 | """ 21 | Expand the search tree horizontally. 22 | i be the scanning index 23 | If s[:i] is palindrome, then palindrome partition the s[i:] 24 | 25 | :param s: the current temp string 26 | :param cur_lvl: the current temp result at current level 27 | :param ret: result 28 | :return: 29 | """ 30 | if not s: 31 | ret.append(list(cur_lvl)) 32 | 33 | for i in xrange(1, len(s)+1): 34 | if self.predicate(s[:i]): 35 | cur_lvl.append(s[:i]) 36 | self.backtrack(s[i:], cur_lvl, ret) 37 | cur_lvl.pop() 38 | 39 | def predicate(self, s): 40 | return s == s[::-1] 41 | 42 | 43 | if __name__ == "__main__": 44 | assert Solution().partition("aabbc") == [['a', 'a', 'b', 'b', 'c'], ['a', 'a', 'bb', 'c'], ['aa', 'b', 'b', 'c'], ['aa', 'bb', 'c']] -------------------------------------------------------------------------------- /Permutation Index II.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a permutation which may contain repeated numbers, find its index in all the permutations of these numbers, which 3 | are ordered in lexicographical order. The index begins at 1. 4 | 5 | Example 6 | Given the permutation [1, 4, 2, 2], return 3. 7 | """ 8 | from collections import defaultdict 9 | 10 | __author__ = 'Daniel' 11 | 12 | 13 | class Solution(object): 14 | def permutationIndexII(self, A): 15 | """ 16 | TODO 17 | """ 18 | idx = 0 19 | factor = 1 20 | cnt = defaultdict(int) 21 | 22 | cnt[A[-1]] += 1 23 | n = len(A) 24 | for i in xrange(n-2, -1, -1): 25 | cnt[A[i]] += 1 # counter at current position, not full A. 26 | for k, v in cnt.items(): 27 | if k < A[i]: 28 | idx += v * factor / cnt[A[i]] 29 | 30 | factor = factor * (n-i) / cnt[A[i]] 31 | 32 | return idx+1 33 | 34 | if __name__ == "__main__": 35 | print Solution().permutationIndexII([1, 4, 2, 2]) 36 | -------------------------------------------------------------------------------- /Permutation Index.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a permutation which contains no repeated number, find its index in all the permutations of these numbers, which 3 | are ordered in lexicographical order. The index begins at 1. 4 | 5 | Given [1,2,4], return 1. 6 | """ 7 | import math 8 | 9 | __author__ = 'Daniel' 10 | 11 | 12 | class Solution: 13 | def permutationIndex(self, A): 14 | """ 15 | Cantor expansion 16 | 17 | Inversions: O(n^2) or O(n lg n) 18 | O(n) count 19 | """ 20 | n = len(A) 21 | idx = 0 22 | for i, v in enumerate(A): 23 | inv = 0 24 | for j in xrange(i+1, n): 25 | if A[i] > A[j]: 26 | inv += 1 27 | 28 | idx += inv * math.factorial(n-1-i) 29 | 30 | return idx+1 31 | -------------------------------------------------------------------------------- /Permutation Sequence.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given n and k, return the k-th permutation sequence. 3 | 4 | Example 5 | For n = 3, all permutations are listed as follows: 6 | 7 | "123" 8 | "132" 9 | "213" 10 | "231" 11 | "312" 12 | "321" 13 | If k = 4, the fourth permutation is "231" 14 | 15 | Note 16 | n will be between 1 and 9 inclusive. 17 | 18 | Challenge 19 | O(n*k) in time complexity is easy, can you do it in O(n^2) or less? 20 | """ 21 | import math 22 | 23 | __author__ = 'Daniel' 24 | 25 | 26 | class Solution: 27 | def getPermutation(self, n, k): 28 | k -= 1 # start from 0 29 | 30 | array = range(1, n+1) 31 | k %= math.factorial(n) 32 | ret = [] 33 | for i in xrange(n-1, -1, -1): 34 | idx, k = divmod(k, math.factorial(i)) 35 | ret.append(array.pop(idx)) 36 | 37 | return "".join(map(str, ret)) -------------------------------------------------------------------------------- /Post Office Problem.py: -------------------------------------------------------------------------------- 1 | """ 2 | On one line there are n houses. Give you an array of integer means the the position of each house. Now you need to pick 3 | k position to build k post office, so that the sum distance of each house to the nearest post office is the smallest. 4 | Return the least possible sum of all distances between each village and its nearest post office. 5 | 6 | Example 7 | Given array a = [1,2,3,4,5], k = 2. return 3. 8 | 9 | Challenge 10 | Could you solve this problem in O(n^2) time ? 11 | """ 12 | __author__ = 'Daniel' 13 | 14 | 15 | class Solution: 16 | def postOffice_TLE(self, A, K): 17 | """ 18 | dp 19 | O(n^3), TLE 20 | :type A: list[int] 21 | :type K: int 22 | :rtype: int 23 | """ 24 | A.sort() 25 | N = len(A) 26 | F = [[0 for _ in xrange(K+1)] for _ in xrange(N+1)] 27 | c = [[0 for _ in xrange(N+1)] for _ in xrange(N+1)] # [i, j) 28 | 29 | for i in xrange(N): 30 | for j in xrange(i+1, N+1): 31 | m = (i+j)/2 32 | for l in xrange(i, j): 33 | c[i][j] += abs(A[m]-A[l]) 34 | 35 | for n in xrange(1, N+1): 36 | F[n][1] = c[0][n] 37 | 38 | for n in xrange(1, N+1): 39 | for k in xrange(2, K+1): 40 | F[n][k] = min( 41 | F[l][k-1]+c[l][n] for l in xrange(n) 42 | ) 43 | 44 | return F[N][K] 45 | 46 | def postOffice_TLE(self, A, K): 47 | """ 48 | dp 49 | O(n^2) using quadratic inequality 50 | :type A: list[int] 51 | :type K: int 52 | :rtype: int 53 | """ 54 | # TODO 55 | 56 | 57 | if __name__ == "__main__": 58 | assert Solution().postOffice([112,122,360,311,85,225,405,53,405,43,342,13,588,424,299,37,104,289,404,414], 3) == 673 -------------------------------------------------------------------------------- /Previous Permuation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a list of integers, which denote a permutation. 3 | 4 | Find the previous permutation in ascending order. 5 | 6 | Note 7 | The list may contains duplicate integers. 8 | 9 | Example 10 | For [1,3,2,3], the previous permutation is [1,2,3,3] 11 | 12 | For [1,2,3,4], the previous permutation is [4,3,2,1] 13 | """ 14 | __author__ = 'Danyang' 15 | 16 | 17 | class Solution: 18 | def previousPermuation(self, num): 19 | """ 20 | permutation, reverse operation of next permutation 21 | :param num: a list of integer 22 | :return: a list of integer 23 | """ 24 | n = len(num) 25 | 26 | partition = n-2 27 | while partition >= 0 and num[partition] <= num[partition+1]: 28 | partition -= 1 29 | 30 | if partition < 0: 31 | return num[::-1] 32 | 33 | change = n-1 34 | while change >= 0 and num[change] >= num[partition]: 35 | change -= 1 36 | 37 | num[partition], num[change] = num[change], num[partition] 38 | 39 | # num = num[:partition+1]+num[n-1:partition:-1] 40 | num[partition+1:] = reversed(num[partition+1:]) # direct slice assignment 41 | return num 42 | 43 | 44 | if __name__ == "__main__": 45 | print Solution().previousPermuation([1, 3, 2, 3]) 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Print Numbers by Recursion.py: -------------------------------------------------------------------------------- 1 | """ 2 | Print numbers from 1 to the largest number with N digits by recursion. 3 | 4 | Have you met this question in a real interview? Yes 5 | Example 6 | Given N = 1, return [1,2,3,4,5,6,7,8,9]. 7 | 8 | Given N = 2, return [1,2,3,4,5,6,7,8,9,10,11,12,...,99]. 9 | 10 | Note 11 | It's pretty easy to do recursion like: 12 | 13 | recursion(i) { 14 | if i > largest number: 15 | return 16 | results.add(i) 17 | recursion(i + 1) 18 | } 19 | however this cost a lot of recursion memory as the recursion depth maybe very large. Can you do it in another way to 20 | recursive with at most N depth? 21 | 22 | Challenge 23 | Do it in recursion, not for-loop. 24 | """ 25 | __author__ = 'Daniel' 26 | 27 | 28 | class Solution(object): 29 | def numbersByRecursion(self, n): 30 | return self.rec(n) 31 | 32 | def rec(self, n): 33 | if n == 0: 34 | return [] 35 | if n == 1: 36 | return [i+1 for i in xrange(9)] 37 | else: 38 | lst = self.rec(n-1) 39 | l = len(lst) 40 | cur = [] 41 | prev = lst[-1]+1 42 | for i in xrange(prev-prev/10): 43 | for j in xrange(10): 44 | cur.append(lst[prev/10-1+i]*10+j) 45 | 46 | lst.extend(cur) 47 | return lst 48 | 49 | if __name__ == "__main__": 50 | print Solution().numbersByRecursion(2) 51 | assert Solution().numbersByRecursion(2) == [i+1 for i in xrange(99)] -------------------------------------------------------------------------------- /Product of Array Exclude Itself.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integers array A. 3 | 4 | Define B[i] = A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1], calculate B without divide operation. 5 | 6 | Example 7 | For A=[1, 2, 3], B is [6, 3, 2] 8 | """ 9 | __author__ = 'Danyang' 10 | 11 | 12 | class Solution: 13 | def productExcludeItself(self, A): 14 | """ 15 | dp array to store the cumulative products 16 | 17 | :param A: Given an integers array A 18 | :return: An integer array B and B[i]= A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1] 19 | """ 20 | n = len(A) 21 | if n == 1: 22 | return [] 23 | 24 | dp = [[1, 1] for _ in xrange(n)] 25 | for i in xrange(1, n): 26 | dp[i][0] = A[i-1]*dp[i-1][0] 27 | dp[n-i-1][1] = A[n-i]*dp[n-i][1] 28 | 29 | B = [dp[i][0]*dp[i][1] for i in xrange(n)] 30 | return B 31 | 32 | if __name__=="__main__": 33 | assert Solution().productExcludeItself([1, 2, 3]) == [6, 3, 2] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LintCode ![Language](https://img.shields.io/badge/language-Python-blue.svg) ![License](https://img.shields.io/badge/license-Apache-red.svg) 2 | Python in Action. 3 | 4 | ## Contents 5 | Only unique questions from [LintCode](https://github.com/algorhythms/LintCode) are included. Duplicated questions of [LeetCode](https://github.com/idf/LeetCode) are excluded, which can be found in [ https://github.com/idf/LeetCode](https://github.com/idf/LeetCode) instead. 6 | ### Python 7 | This repo mainly uses Python. To run in Python: 8 | ```bash 9 | python .py 10 | ``` 11 | If you encountered `Class Already Defined` compilation problem in OJ, please remove `TreeNode`, `GraphNode` or etc. 12 | ### Java 13 | Some algorithms in Python cannot pass the OJ due to OJ bugs; thus the alternative solutions in java in the exactly same algorithm are provided. To run in Java: 14 | ```bash 15 | cd LintCode/java/src/main/java 16 | javac /Solution.java 17 | java -ea /Solution # -ea: enable assertion 18 | ``` 19 | ### Notes: TLE & MLE 20 | Failed attempts are kept in the source code as documentation, which are annotated as TLE (Time Limit Exceeds) or MLE (Memory Limit Exceeds). 21 | 22 | ## Online Judges 23 | * [LintCode OJ](http://lintcode.com/en/daily/) 24 | * [LeetCode OJ](https://oj.leetcode.com/problems/) 25 | 26 | ## LintCode Copyright 27 | Most of the code are from the section tag of [LintCode Copyright](http://lintcode.com/tag/lintcode-copyright) 28 | -------------------------------------------------------------------------------- /Rehashing.py: -------------------------------------------------------------------------------- 1 | """ 2 | The size of the hash table is not determinate at the very beginning. If the total size of keys is too large (e.g. size 3 | >= capacity / 10), we should double the size of the hash table and rehash every keys. Say you have a hash table looks 4 | like below: 5 | 6 | size=3, capacity=4 7 | [null, 21->9->null, 14->null, null] 8 | 9 | The hash function is: 10 | 11 | int hashcode(int key, int capacity) { 12 | return key % capacity; 13 | } 14 | 15 | here we have three numbers, 9, 14 and 21, where 21 and 9 share the same position as they all have the same hashcode 1 16 | (21 % 4 = 9 % 4 = 1). We store them in the hash table by linked list. 17 | 18 | rehashing this hash table, double the capacity, you will get: 19 | 20 | size=3, capacity=8 21 | index: 0 1 2 3 4 5 6 7 22 | hash table: [null, 9, null, null, null, 21, 14, null] 23 | 24 | Given the original hash table, return the new hash table after rehashing . 25 | """ 26 | __author__ = 'Danyang' 27 | 28 | 29 | class ListNode(object): 30 | def __init__(self, val, next=None): 31 | self.val = val 32 | self.next = next 33 | 34 | def __repr__(self): 35 | return repr(self.val) 36 | 37 | 38 | class Solution: 39 | def rehashing(self, hashTable): 40 | """ 41 | 42 | :param hashTable: A list of The first node of linked list 43 | :return: A list of The first node of linked list which have twice size 44 | """ 45 | cap = len(hashTable) 46 | cap *= 2 47 | ht = [None for _ in xrange(cap)] 48 | for node in hashTable: 49 | while node: 50 | self.__rehash(ht, ListNode(node.val)) # need a new copy 51 | node = node.next 52 | return ht 53 | 54 | def __rehash(self, ht, node): 55 | code = self.__hashcode(node.val, len(ht)) 56 | if ht[code] is None: 57 | ht[code] = node 58 | else: 59 | cur = ht[code] 60 | while cur.next: 61 | cur = cur.next 62 | cur.next = node 63 | 64 | def __hashcode(self, key, capacity): 65 | return key%capacity 66 | 67 | 68 | if __name__ == "__main__": 69 | hashTable = [None for _ in xrange(3)] 70 | n0 = ListNode(29) 71 | n1 = ListNode(5) 72 | n0.next = n1 73 | hashTable[2] = n0 74 | 75 | print Solution().rehashing(hashTable) -------------------------------------------------------------------------------- /Remove Node in Binary Search Tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a root of Binary Search Tree with unique value for each node. Remove the node with given value. If there is no 3 | such a node with given value in the binary search tree, do nothing. You should keep the tree still a binary search tree 4 | after removal. 5 | """ 6 | __author__ = 'Danyang' 7 | 8 | 9 | class TreeNode: 10 | def __init__(self, val): 11 | self.val = val 12 | self.left, self.right = None, None 13 | 14 | 15 | class Solution: 16 | def removeNode(self, root, value): 17 | """ 18 | BST: L value: 46 | self.__removeNode(root.left, root, value) 47 | elif root.val < value: 48 | self.__removeNode(root.right, root, value) 49 | else: 50 | if not root.left and not root.right: # no child 51 | if parent: 52 | if parent.left == root: 53 | parent.left = None 54 | else: 55 | parent.right = None 56 | else: 57 | root = None 58 | elif root.left and not root.right or root.right and not root.left: # single child 59 | if root.left: 60 | if parent: 61 | if parent.left == root: 62 | parent.left = root.left 63 | else: 64 | parent.right = root.left 65 | else: # when val at root of entire tree 66 | root = root.left 67 | else: 68 | if parent: 69 | if parent.left == root: 70 | parent.left = root.right 71 | else: 72 | parent.right = root.right 73 | else: # when val at root of entire tree 74 | root = root.right 75 | else: # two children 76 | cur = root.left 77 | while cur.right: 78 | cur = cur.right 79 | root.val = cur.val 80 | # go down again 81 | self.__removeNode(root.left, root, cur.val) 82 | 83 | return root -------------------------------------------------------------------------------- /Rotate List.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a list, rotate the list to the right by k places, where k is non-negative. 3 | 4 | Example 5 | Given 1->2->3->4->5 and k = 2, return 4->5->1->2->3. 6 | """ 7 | __author__ = 'Daniel' 8 | 9 | 10 | class ListNode: 11 | def __init__(self, x): 12 | self.val = x 13 | self.next = None 14 | 15 | 16 | class Solution: 17 | def rotateRight(self, head, k): 18 | if not head: 19 | return head 20 | 21 | dummy = ListNode(0) 22 | dummy.next = head 23 | l = self.get_len(head) 24 | k %= l # pitfall, ask to clarify k 25 | pre = dummy 26 | i = 0 27 | while pre and i < l-k: 28 | pre = pre.next 29 | i += 1 30 | 31 | new_head = pre.next 32 | if not new_head: 33 | return dummy.next 34 | 35 | cur = new_head 36 | pre.next = None 37 | while cur.next: 38 | cur = cur.next 39 | 40 | cur.next = dummy.next 41 | dummy.next = new_head 42 | return dummy.next 43 | 44 | def get_len(self, head): 45 | l = 0 46 | cur = head 47 | while cur: 48 | l += 1 49 | cur = cur.next 50 | 51 | return l 52 | 53 | 54 | -------------------------------------------------------------------------------- /Route Between Two Nodes in Graph.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a directed graph, design an algorithm to find out whether there is a route between two nodes. 3 | 4 | Example 5 | Given graph: 6 | 7 | A----->B----->C 8 | \ | 9 | \ | 10 | \ | 11 | \ v 12 | ->D----->E 13 | for s = B and t = E, return true 14 | 15 | for s = D and t = C, return false 16 | """ 17 | __author__ = 'Daniel' 18 | 19 | 20 | class DirectedGraphNode: 21 | def __init__(self, x): 22 | self.label = x 23 | self.neighbors = [] 24 | 25 | 26 | class Solution(object): 27 | def hasRoute(self, graph, s, t): 28 | visited = set() 29 | return self.dfs(s, t, visited) 30 | 31 | def dfs(self, s, t, visited): 32 | """pre-check""" 33 | if s == t: 34 | return True 35 | 36 | visited.add(s) 37 | for nbr in s.neighbors: 38 | if nbr not in visited: 39 | if self.dfs(nbr, t, visited): 40 | return True 41 | 42 | return False 43 | 44 | -------------------------------------------------------------------------------- /Search Range in Binary Search Tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two values k1 and k2 (where k1 < k2) and a root pointer to a Binary Search Tree. Find all the keys of tree in 3 | range k1 to k2. i.e. print all x such that k1<=x<=k2 and x is a key of given BST. Return all the keys in ascending 4 | order. 5 | 6 | Example 7 | If k1 = 10 and k2 = 22, then your function should return [12, 20, 22]. 8 | 9 | 20 10 | / \ 11 | 8 22 12 | / \ 13 | 4 12 14 | """ 15 | __author__ = 'Daniel' 16 | 17 | 18 | class TreeNode: 19 | def __init__(self, val): 20 | self.val = val 21 | self.left, self.right = None, None 22 | 23 | 24 | class Solution(object): 25 | def searchRange(self, root, k1, k2): 26 | ret = [] 27 | self.dfs(root, k1, k2, ret) 28 | return ret 29 | 30 | def dfs(self, root, k1, k2, ret): 31 | if not root: 32 | return 33 | 34 | if root.val < k1: 35 | self.dfs(root.right, k1, k2, ret) 36 | elif root.val > k2: 37 | self.dfs(root.left, k1, k2, ret) 38 | else: 39 | self.dfs(root.left, k1, k2, ret) 40 | ret.append(root.val) 41 | self.dfs(root.right, k1, k2, ret) -------------------------------------------------------------------------------- /Segment Tree Build.py: -------------------------------------------------------------------------------- 1 | """ 2 | The structure of Segment Tree is a binary tree which each node has two attributes start and end denote an segment / 3 | interval. 4 | 5 | start and end are both integers, they should be assigned in following rules: 6 | 7 | The root's start and end is given by build method. 8 | The left child of node A has start=A.left, end=(A.left + A.right) / 2. 9 | The right child of node A has start=(A.left + A.right) / 2, end=A.right. 10 | if start equals to end, there will be no children for this node. 11 | Implement a build method with two parameters start and end, so that we can create a corresponding segment tree with 12 | every node has the correct start and end value, return the root of this segment tree. 13 | """ 14 | __author__ = 'Danyang' 15 | 16 | 17 | class SegmentTreeNode: 18 | def __init__(self, start, end): 19 | self.start, self.end = start, end 20 | self.left, self.right = None, None 21 | 22 | 23 | class Solution: 24 | def build(self, start, end): 25 | """ 26 | 27 | :param start, end: denote an segment / interval 28 | :return: The root of Segment Tree 29 | """ 30 | if start > end: 31 | return None 32 | 33 | root = SegmentTreeNode(start, end) 34 | if start == end: 35 | return root 36 | 37 | root.left = self.build(start, (start+end)/2) 38 | root.right = self.build((start+end)/2+1, end) 39 | return root 40 | -------------------------------------------------------------------------------- /Segment Tree Modify.py: -------------------------------------------------------------------------------- 1 | """ 2 | For a Maximum Segment Tree, which each node has an extra value max to store the maximum value in this node's interval. 3 | 4 | Implement a modify function with three parameter root, index and value to change the node's value with [start, end] = 5 | [index, index] to the new given value. Make sure after this change, every node in segment tree still has the max 6 | attribute with the correct value. 7 | """ 8 | __author__ = 'Danyang' 9 | 10 | 11 | class SegmentTreeNode: 12 | def __init__(self, start, end, max): 13 | self.start, self.end, self.max = start, end, max 14 | self.left, self.right = None, None 15 | 16 | 17 | class Solution: 18 | def modify(self, root, index, value): 19 | """ 20 | need bottom-up update the max 21 | :type root: SegmentTreeNode 22 | :param root: The root of segment tree and 23 | :param index: change the node's value with [index, index] to the new given value 24 | :param value: the new given value 25 | :return: void 26 | """ 27 | if root is None: 28 | return 29 | if index < root.start or index > root.end: 30 | return 31 | if root.start == index and root.end == index: 32 | root.max = value 33 | return 34 | 35 | # bottom up 36 | self.modify(root.left, index, value) 37 | self.modify(root.right, index, value) 38 | 39 | m = value 40 | if root.left: 41 | m = max(m, root.left.max) 42 | if root.right: 43 | m = max(m, root.right.max) 44 | root.max = m 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Segment Tree Query II.py: -------------------------------------------------------------------------------- 1 | """ 2 | For an array, we can build a SegmentTree for it, each node stores an extra attribute count to denote the number of 3 | elements in the the array which value is between interval start and end. (The array may not fully filled by elements) 4 | 5 | Design a query method with three parameters root, start and end, find the number of elements in the in array's interval 6 | [start, end] by the given root of value SegmentTree. 7 | 8 | Have you met this question in a real interview? Yes 9 | Example 10 | For array [0, empty, 2, 3], the corresponding value Segment Tree is: 11 | 12 | [0, 3, count=3] 13 | / \ 14 | [0,1,count=1] [2,3,count=2] 15 | / \ / \ 16 | [0,0,count=1] [1,1,count=0] [2,2,count=1], [3,3,count=1] 17 | query(1, 1), return 0 18 | 19 | query(1, 2), return 1 20 | 21 | query(2, 3), return 2 22 | 23 | query(0, 2), return 2 24 | """ 25 | __author__ = 'Daniel' 26 | DEFAULT = 0 27 | f = lambda x, y: x+y 28 | 29 | 30 | class Solution: 31 | def query(self, root, s, e): 32 | """ 33 | Segment: [s, e] 34 | 35 | :param root: The root of segment tree 36 | :param start: start of segment/interval 37 | :param end: end of segment/interval 38 | :return: The count number in the interval [start, end] 39 | """ 40 | if not root: 41 | return DEFAULT 42 | 43 | if s <= root.start and e >= root.end: 44 | return root.count 45 | 46 | if s > root.end or e < root.start: 47 | return DEFAULT 48 | 49 | l = self.query(root.left, s, e) 50 | r = self.query(root.right, s, e) 51 | return f(l, r) 52 | -------------------------------------------------------------------------------- /Segment Tree Query.py: -------------------------------------------------------------------------------- 1 | """ 2 | For an integer array (index from 0 to n-1, where n is the size of this array), in the corresponding SegmentTree, each 3 | node stores an extra attribute max to denote the maximum number in the interval of the array (index from start to end). 4 | 5 | Design a query method with three parameters root, start and end, find the maximum number in the interval [start, end] by 6 | the given root of segment tree. 7 | """ 8 | __author__ = 'Danyang' 9 | import sys 10 | 11 | 12 | class SegmentTreeNode: 13 | def __init__(self, start, end, max): 14 | self.start, self.end, self.max = start, end, max 15 | self.left, self.right = None, None 16 | 17 | 18 | class Solution: 19 | def query(self, root, start, end): 20 | """ 21 | 22 | :param root, start, end: The root of segment tree and an segment / interval 23 | :return: The maximum number in the interval [start, end] 24 | """ 25 | 26 | if start <= root.start and end >= root.end: # the start and end remain unchanged during the query. 27 | return root.max 28 | if start > end: 29 | return -sys.maxint-1 30 | 31 | maxa = -sys.maxint-1 32 | if root.left: 33 | left = self.query(root.left, start, end) 34 | maxa = max(maxa, left) 35 | if root.right: 36 | right = self.query(root.right, start, end) 37 | maxa = max(maxa, right) 38 | 39 | return maxa 40 | 41 | -------------------------------------------------------------------------------- /Single Number III.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given 2*n + 2 numbers, every numbers occurs twice except two, find them. 3 | 4 | Example 5 | Given [1,2,2,3,4,4,5,3] return 1 and 5 6 | 7 | Challenge 8 | O(n) time, O(1) extra space. 9 | """ 10 | __author__ = 'Danyang' 11 | 12 | 13 | class Solution: 14 | def singleNumberIII(self, A): 15 | """ 16 | Bit manipulation 17 | If two numbers are different, \exists 1 bit set in one while unset in the other. 18 | 19 | To get the rightmost set bit: n&(~n+1), which is equivalent to n&-n (2's complement) 20 | 21 | :param A: An integer array 22 | :return: Two integer 23 | """ 24 | bits = 0 25 | for a in A: 26 | bits ^= a 27 | 28 | rightmost_set_bit = bits&-bits 29 | 30 | bits1 = 0 31 | bits2 = 0 32 | for a in A: 33 | if a&rightmost_set_bit: 34 | bits1 ^= a 35 | else: 36 | bits2 ^= a 37 | 38 | return bits1, bits2 39 | 40 | 41 | -------------------------------------------------------------------------------- /Singleton.py: -------------------------------------------------------------------------------- 1 | """ 2 | Singleton is a most widely used design pattern. If a class has and only has one instance at every moment, we call this 3 | design as singleton. For example, for class Mouse (not a animal mouse), we should design it in singleton. 4 | 5 | You job is to implement a getInstance method for given class, return the same instance of this class every time you call 6 | this method. 7 | 8 | Example 9 | In Java: 10 | 11 | A a = A.getInstance(); 12 | A b = A.getInstance(); 13 | a should equal to b. 14 | 15 | Challenge 16 | If we call getInstance concurrently, can you make sure your code could run correctly? 17 | """ 18 | import threading 19 | __author__ = 'Daniel' 20 | 21 | 22 | class Solution_unsafe: 23 | obj = None 24 | @classmethod 25 | def getInstance(cls): 26 | """ 27 | 28 | :return: The same instance of this class every time 29 | """ 30 | if not Solution.obj: 31 | Solution.obj = cls() 32 | return Solution.obj 33 | 34 | 35 | class Solution: 36 | __lock = threading.Lock() 37 | __obj = None 38 | 39 | @classmethod 40 | def getInstance(cls): 41 | if not cls.__obj: 42 | with cls.__lock: 43 | if not cls.__obj: 44 | cls.__obj = cls() 45 | 46 | return cls.__obj 47 | -------------------------------------------------------------------------------- /Sliding Window Maximum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of n integer with duplicate number, and a moving window(size k), move the window at each iteration from 3 | the start of the array, find the maximum number inside the window at each moving. 4 | 5 | Example 6 | For array [1, 2, 7, 7, 8], moving window size k = 3. return [7, 7, 8] 7 | 8 | 9 | """ 10 | __author__ = 'Daniel' 11 | 12 | 13 | class Solution: 14 | def maxSlidingWindow(self, nums, k): 15 | """ 16 | Sliding window + queue 17 | The queue keeps only the valuable information, while useless information is deleted 18 | 19 | http://articles.leetcode.com/2011/01/sliding-window-maximum.html 20 | The more recent the index is, the more valuable the data is 21 | 22 | Notice: 23 | * Loop invariant: the queue is keeping the index of max elements TO THE RIGHT under the window 24 | * the queue is storing the index 25 | 26 | :param nums: A list of integers. 27 | :param k: 28 | :return: The maximum number inside the window at each moving. 29 | """ 30 | if not nums or k == 0: 31 | return [] 32 | 33 | q = [] 34 | ret = [] 35 | for i in xrange(k): 36 | while q and nums[i] >= nums[q[-1]]: 37 | q.pop() 38 | q.append(i) 39 | ret.append(nums[q[0]]) # init 40 | 41 | for i in xrange(k, len(nums)): # starting from k for the end of window 42 | while q and nums[i] >= nums[q[-1]]: 43 | q.pop() 44 | while q and q[0] < i-k+1: # plus 1 45 | q.pop(0) 46 | q.append(i) 47 | ret.append(nums[q[0]]) 48 | 49 | return ret 50 | 51 | 52 | if __name__ == "__main__": 53 | print Solution().maxSlidingWindow([1, 2, 7, 7, 8], 3) -------------------------------------------------------------------------------- /Sort Letters by Case.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string which contains only letters. Sort it by lower case first and upper case second. 3 | 4 | Note 5 | It's not necessary to keep the original order of lower-case letters and upper case letters. 6 | 7 | Example 8 | For "abAcD", a reasonable answer is "acbAD" 9 | """ 10 | __author__ = 'Danyang' 11 | 12 | 13 | class Solution: 14 | def sortLetters(self, chars): 15 | """ 16 | General sort: O(n lg n) 17 | But in this case, the possible elements are in a closed set - either lower case or upper case; thus O(n) 18 | 19 | The array is abstracted to | closed set | open set |, and move all lower case letters into closed set. 20 | 21 | :param chars: The letters array you should sort. 22 | :return: NIL, in-place 23 | """ 24 | closed = -1 25 | for ind, val in enumerate(chars): 26 | if ord(val) < ord('a'): # ASCII A-Za-z 27 | continue 28 | else: 29 | closed += 1 30 | chars[ind], chars[closed] = chars[closed], chars[ind] 31 | 32 | 33 | if __name__ == "__main__": 34 | chars = list("abAcD") 35 | Solution().sortLetters(chars) 36 | assert "".join(chars) == "abcAD" -------------------------------------------------------------------------------- /Space Replacement.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write a method to replace all spaces in a string with %20. The string is given in a characters array, you can assume it 3 | has enough space for replacement and you are given the true length of the string. 4 | 5 | Example 6 | Given "Mr John Smith", length = 13. 7 | 8 | The string after replacement should be "Mr%20John%20Smith". 9 | 10 | Note 11 | If you are using Java or Python, please use characters array instead of string. 12 | 13 | Challenge 14 | Do it in-place. 15 | """ 16 | __author__ = 'Daniel' 17 | 18 | 19 | class Solution: 20 | def replaceBlank(self, string, length): 21 | """ 22 | 23 | :param string: An array of Char 24 | :param length: The true length of the string 25 | :return: The true length of new string 26 | """ 27 | i = 0 28 | while i < length: 29 | if string[i] == " ": 30 | string.append("") 31 | string.append("") 32 | length += 2 33 | for j in xrange(length-1, i, -1): 34 | string[j] = string[j-2] 35 | 36 | string[i:i+3] = list("%20") 37 | i += 2 38 | i += 1 39 | 40 | return length 41 | 42 | if __name__ == "__main__": 43 | assert Solution().replaceBlank(list("Mr John Smith"), 13) == 17 -------------------------------------------------------------------------------- /Subarray Sum II.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array, find a subarray where the sum of numbers is between two given interval. Your code should return 3 | the number of possible answer. 4 | 5 | Have you met this question in a real interview? Yes 6 | Example 7 | Given [1,2,3,4] and interval = [1,3], return 4. The possible answers are: 8 | 9 | [0, 0] 10 | [0, 1] 11 | [1, 1] 12 | [3, 3] 13 | 14 | """ 15 | __author__ = 'Daniel' 16 | from bisect import bisect_left, bisect_right 17 | 18 | 19 | class Solution: 20 | def subarraySumII(self, A, start, end): 21 | """ 22 | O(n lg n) Binary Search 23 | Bound: 24 | f[i] - f[j] = start 25 | f[i] - f[j'] = end 26 | start < end 27 | f[j] > f[j'] 28 | 29 | :param A: an integer array 30 | :param start: start an integer 31 | :param end: end an integer 32 | :return: 33 | """ 34 | n = len(A) 35 | cnt = 0 36 | f = [0 for _ in xrange(n+1)] 37 | 38 | for i in xrange(1, n+1): 39 | f[i] = f[i-1]+A[i-1] # from left 40 | 41 | f.sort() 42 | for i in xrange(n+1): 43 | lo = bisect_left(f, f[i]-end, 0, i) 44 | hi = bisect_right(f, f[i]-start, 0, i) 45 | cnt += hi-lo # 0----lo----hi-----END 46 | 47 | return cnt 48 | 49 | def subarraySumII_TLE(self, A, start, end): 50 | """ 51 | O(n^2) 52 | 53 | :param A: an integer array 54 | :param start: start an integer 55 | :param end: end an integer 56 | :return: 57 | """ 58 | n = len(A) 59 | cnt = 0 60 | f = [0 for _ in xrange(n+1)] 61 | 62 | for i in xrange(1, n+1): 63 | f[i] = f[i-1]+A[i-1] # from left 64 | 65 | for i in xrange(0, n+1): 66 | for j in xrange(i+1, n+1): 67 | s = f[j]-f[i] 68 | if start <= s <= end: 69 | cnt += 1 70 | 71 | return cnt 72 | 73 | 74 | if __name__ == "__main__": 75 | assert Solution().subarraySumII([1, 2, 3, 4], 1, 3) == 4 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Subarray Sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array, find a subarray where the sum of numbers is zero. Your code should return the index of the first 3 | number and the index of the last number. 4 | 5 | Example 6 | Given [-3, 1, 2, -3, 4], return [0, 2] or [1, 3]. 7 | 8 | Note 9 | There is at least one subarray that it's sum equals to zero. 10 | """ 11 | __author__ = 'Daniel' 12 | from collections import defaultdict 13 | 14 | 15 | class Solution: 16 | def subarraySum(self, nums): 17 | """ 18 | DP: 19 | DP + Hash 20 | reduce from O(n^2) to O(n) 21 | 22 | :param nums: A list of integers 23 | :return: A list of integers includes the index of the first number and the index of the last number 24 | """ 25 | n = len(nums) 26 | f = [0 for _ in xrange(n+1)] 27 | for i in xrange(1, n+1): 28 | f[i] = f[i-1]+nums[i-1] 29 | 30 | d = defaultdict(list) 31 | for i in xrange(1, n+1): 32 | d[f[i]].append(i) 33 | 34 | for k, v in d.items(): 35 | if k == 0: 36 | return [0, v[0]-1] 37 | if len(v) > 1: 38 | return [v[0], v[1]-1] 39 | 40 | return [-1, -1] 41 | 42 | 43 | if __name__ == "__main__": 44 | print Solution().subarraySum([-5, 10, 5, -3, 1, 1, 1, -2, 3, -4]) -------------------------------------------------------------------------------- /Submatrix Sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer matrix, find a submatrix where the sum of numbers is zero. Your code should return the coordinate of 3 | the left-up and right-down number. 4 | 5 | Example 6 | Given matrix 7 | 8 | [ 9 | [1 ,5 ,7], 10 | [3 ,7 ,-8], 11 | [4 ,-8 ,9], 12 | ] 13 | return [(1,1), (2,2)] 14 | 15 | Challenge 16 | O(n^3) time. 17 | """ 18 | __author__ = 'Daniel' 19 | 20 | 21 | class Solution: 22 | def submatrixSum(self, matrix): 23 | """ 24 | dp O(n^3) 25 | Set the floor and ceiling inside the matrix, and then scan the subcolumns in between the ceiling and the floor 26 | 27 | :param matrix: an integer matrix 28 | :return: the coordinate of the left-up and right-down number 29 | """ 30 | m = len(matrix) 31 | n = len(matrix[0]) 32 | to_top = [[0 for _ in xrange(n+1)] for _ in xrange(m+1)] # the sum of sub-column starting from row=0 to row=i 33 | for i in xrange(1, m+1): 34 | for j in xrange(1, n+1): 35 | to_top[i][j] = to_top[i-1][j] + matrix[i-1][j-1] 36 | 37 | for up in xrange(m): 38 | for down in xrange(up, m): 39 | h = {} # map to store the previous sub-column sum 40 | s = 0 41 | h[s] = -1 # edge case 42 | for j in xrange(n): 43 | s += to_top[down+1][j+1] - to_top[up][j+1] 44 | if s in h: 45 | return [[up, h[s]+1], [down, j]] 46 | h[s] = j 47 | 48 | return [[-1, -1], [-1, -1]] 49 | 50 | if __name__ == "__main__": 51 | assert Solution().submatrixSum([ 52 | [1, 5, 7], 53 | [3, 7, -8], 54 | [4, -8, 9], 55 | ]) == [[1, 1], [2, 2]] 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /The Smallest Difference.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two array of integers(the first array is array A, the second array is array B), now we are going to find a element 3 | in array A which is A[i], and another element in array B which is B[j], so that the difference between A[i] and B[j] 4 | (|A[i] - B[j]|) is as small as possible, return their smallest difference. 5 | """ 6 | __author__ = 'Daniel' 7 | import sys 8 | 9 | 10 | class Solution: 11 | def smallestDifference(self, A, B): 12 | """ 13 | O(n lg n) 14 | Binary search 15 | :param A: list[int] 16 | :param B: list[int] 17 | :return: int 18 | """ 19 | A.sort() 20 | B.sort() 21 | ret = sys.maxint 22 | for a in A: 23 | idx = self.bin_search(a, B) 24 | ret = min(ret, abs(a-B[idx])) 25 | if idx+1t: 44 | u = m 45 | else: 46 | l = m+1 # if A[m]B in graph, A must before B in the order list. 5 | The first node in the order can be any node in the graph with no nodes direct to it. 6 | Find any topological order for the given graph. 7 | 8 | Note 9 | You can assume that there is at least one topological order in the graph. 10 | """ 11 | __author__ = 'Danyang' 12 | class DirectedGraphNode: 13 | def __init__(self, x): 14 | self.label = x 15 | self.neighbors = [] 16 | 17 | class Solution: 18 | def topSort_error(self, graph): 19 | """ 20 | 21 | :param graph: 22 | :return: graph 23 | """ 24 | node2neighbors = {} 25 | for node in graph: 26 | node2neighbors[node] = set(node.neighbors) 27 | 28 | # error, edge is transitive 29 | def cmp(a, b): 30 | if a in node2neighbors[b]: 31 | return 1 32 | if b in node2neighbors[a]: 33 | return -1 34 | return 0 35 | 36 | graph.sort(cmp=cmp) 37 | return graph 38 | 39 | def topSort_normal(self, graph): 40 | """ 41 | Without dfs/bfs 42 | 43 | 1. get all the predecessors of each node 44 | 2. pop a node without a predecessors and add it to result list 45 | 3. update the predecessors of each node 46 | 47 | :param graph: A list of Directed graph node 48 | :return: graph 49 | """ 50 | pi = {} 51 | for node in graph: 52 | pi[node] = set() 53 | 54 | for node in graph: 55 | for nbr in node.neighbors: 56 | pi[nbr].add(node) 57 | 58 | ret = [] 59 | while graph: 60 | i = 0 61 | while ic 29 | Fix the higher pointer; two other pointers are set at start and end respectively and converge them. 30 | The converging two pointers should be in the same side of triangle inequality 31 | 32 | :param S: a list of integers 33 | :return: a integer 34 | """ 35 | S.sort() 36 | cnt = 0 37 | for h in xrange(len(S)-1, 1, -1): 38 | s = 0 39 | e = h-1 40 | while sS[h]: 42 | cnt += e-s 43 | e -= 1 44 | else: 45 | s += 1 46 | 47 | return cnt 48 | 49 | if __name__ == "__main__": 50 | assert Solution().triangleCount([3, 4, 6, 7]) == 3 -------------------------------------------------------------------------------- /Unique Binary Search Trees II.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given n, generate all structurally unique BST's (binary search trees) that store values 1...n. 3 | 4 | Have you met this question in a real interview? Yes 5 | Example 6 | Given n = 3, your program should return all 5 unique BST's shown below. 7 | 8 | 1 3 3 2 1 9 | \ / / / \ \ 10 | 3 2 1 1 3 2 11 | / / \ \ 12 | 2 1 2 3 13 | """ 14 | __author__ = 'Daniel' 15 | 16 | 17 | class TreeNode(object): 18 | def __init__(self, val): 19 | self.val = val 20 | self.left, self.right = None, None 21 | 22 | 23 | class Solution(object): 24 | def generateTrees(self, n): 25 | """ 26 | :type n: int 27 | :rtype: List[TreeNode] 28 | """ 29 | return self.dfs(1, n+1) 30 | 31 | def dfs(self, s, e): 32 | ret = [] 33 | if s >= e: 34 | return [None] 35 | 36 | for i in xrange(s, e): 37 | ls = self.dfs(s, i) 38 | rs = self.dfs(i+1, e) 39 | for l in ls: 40 | for r in rs: 41 | root = TreeNode(i) 42 | root.left = l 43 | root.right = r 44 | ret.append(root) 45 | 46 | return ret -------------------------------------------------------------------------------- /Unique Binary Search Trees.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given n, how many structurally unique BSTs (binary search trees) that store values 1...n? 3 | 4 | Have you met this question in a real interview? Yes 5 | Example 6 | Given n = 3, there are a total of 5 unique BST's. 7 | 8 | 1 3 3 2 1 9 | \ / / / \ \ 10 | 3 2 1 1 3 2 11 | / / \ \ 12 | 2 1 2 3 13 | """ 14 | __author__ = 'Daniel' 15 | 16 | 17 | class Solution: 18 | def __init__(self): 19 | self.cache = {} 20 | 21 | def numTrees(self, n): 22 | return self.dfs(n) 23 | 24 | def dfs(self, n): 25 | if n not in self.cache: 26 | if n in (0, 1, 2): 27 | self.cache[n] = max(1, n) 28 | else: 29 | s = 0 30 | for i in xrange(1, n+1): 31 | l = self.dfs(i-1) 32 | r = self.dfs(n-i) 33 | s += l*r # multiplication rather than plus 34 | 35 | self.cache[n] = s 36 | 37 | return self.cache[n] 38 | 39 | 40 | if __name__ == "__main__": 41 | print Solution().numTrees(3) -------------------------------------------------------------------------------- /Update Bits.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two 32-bit numbers, N and M, and two bit positions, i and j. Write a method to set all bits between i and j in N 3 | equal to M (e g , M becomes a substring of N located at i and starting at j) 4 | 5 | Example 6 | Given N=(10000000000)2, M=(10101)2, i=2, j=6 7 | 8 | return N=(10001010100)2 9 | """ 10 | __author__ = 'Danyang' 11 | 12 | 13 | class Solution: 14 | def updateBits(self, n, m, i, j): 15 | """ 16 | Notice the operator precedence 17 | 2's complement in Python 18 | 19 | :param n, m: Two integer 20 | :param i, j: Two bit positions, indexes 21 | :return: An integer 22 | """ 23 | mask = ((1<<32)-1)-((1< 0 and val&(1<<(bits-1)) != 0: # not ==1 33 | val -= 1<= k: 40 | lo = m+1 41 | else: 42 | hi = m 43 | 44 | return lo-1 45 | 46 | 47 | if __name__ == "__main__": 48 | assert Solution().woodCut([2147483644, 2147483645, 2147483646, 2147483647], 4) == 2147483644 -------------------------------------------------------------------------------- /archive/Count of Smaller Number before itself.py: -------------------------------------------------------------------------------- 1 | """ 2 | Give you an integer array (index from 0 to n-1, where n is the size of this array, value from 0 to 10000) . For each 3 | element Ai in the array, count the number of element before this element Ai is smaller than it and return count number 4 | array. 5 | 6 | Example 7 | For array [1,2,7,8,5], return [0,1,2,3,2] 8 | 9 | Note 10 | We suggest you finish problem Segment Tree Build, Segment Tree Query II and Count of Smaller Number before itself I 11 | first. 12 | """ 13 | __author__ = 'Daniel' 14 | 15 | 16 | class Node(object): 17 | def __init__(self, val): 18 | """Records the left subtree size""" 19 | self.val = val 20 | self.cnt_left = 0 21 | self.cnt_this = 0 22 | self.left, self.right = None, None 23 | 24 | def __repr__(self): 25 | return repr(self.val) 26 | 27 | 28 | class BST(object): 29 | def __init__(self): 30 | self.root = None 31 | 32 | def insert(self, root, val): 33 | """ 34 | :return: subtree's root after insertion 35 | """ 36 | if not root: 37 | root = Node(val) 38 | 39 | if root.val == val: 40 | root.cnt_this += 1 41 | elif val < root.val: 42 | root.cnt_left += 1 43 | root.left = self.insert(root.left, val) 44 | else: 45 | root.right = self.insert(root.right, val) 46 | 47 | return root 48 | 49 | def rank(self, root, val): 50 | """ 51 | Rank in the root's subtree 52 | :return: number of items smaller than val 53 | """ 54 | if not root: 55 | return 0 56 | if root.val < val: 57 | return root.cnt_this+root.cnt_left+self.rank(root.right, val) 58 | elif root.val == val: 59 | return root.cnt_left 60 | else: 61 | return self.rank(root.left, val) 62 | 63 | 64 | class Solution(object): 65 | def countOfSmallerNumberII(self, A): 66 | """ 67 | TLE in python but the same algorithm in java passed the test cases. 68 | 69 | :param A: A list of integer 70 | :return: Count the number of element before this element 'ai' is smaller than it and return count number list 71 | """ 72 | tree = BST() 73 | ret = [] 74 | for a in A: 75 | tree.root = tree.insert(tree.root, a) 76 | ret.append(tree.rank(tree.root, a)) 77 | 78 | return ret 79 | 80 | 81 | if __name__ == "__main__": 82 | assert Solution().countOfSmallerNumberII( 83 | [26, 78, 27, 100, 33, 67, 90, 23, 66, 5, 38, 7, 35, 23, 52, 22, 83, 51, 98, 69, 81, 32, 78, 28, 94, 13, 2, 97, 84 | 3, 76, 99, 51, 9, 21, 84, 66, 65, 36, 100, 41]) == [0, 1, 1, 3, 2, 3, 5, 0, 4, 0, 5, 1, 6, 2, 9, 2, 14, 10, 17, 85 | 14, 16, 7, 16, 7, 22, 2, 0, 25, 1, 20, 29, 15, 4, 6, 28, 86 | 20, 20, 16, 37, 18] 87 | -------------------------------------------------------------------------------- /archive/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Daniel' 2 | -------------------------------------------------------------------------------- /java/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | LintCode 8 | LintCode 9 | 1.0-SNAPSHOT 10 | 11 | 12 | -------------------------------------------------------------------------------- /java/src/main/java/BuildingOutline/Solution.java: -------------------------------------------------------------------------------- 1 | package BuildingOutline; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * Created by Daniel on 17/06/15. 7 | */ 8 | public class Solution { 9 | class Building implements Comparable{ 10 | int h; 11 | boolean deleted; 12 | Building(int h) { 13 | this.h = h; 14 | this.deleted = false; 15 | } 16 | 17 | 18 | public int compareTo(Building o) { 19 | return o.h - this.h; 20 | } 21 | } 22 | 23 | class Event { 24 | List starts; 25 | List ends; 26 | 27 | Event() { 28 | this.starts = new ArrayList<>(); 29 | this.ends = new ArrayList<>(); 30 | } 31 | } 32 | /** 33 | * @param buildings: A list of lists of integers 34 | * @return: Find the outline of those buildings 35 | */ 36 | public ArrayList> buildingOutline(int[][] buildings) { 37 | SortedMap events = new TreeMap<>(); 38 | for(int[] b: buildings) { 39 | Building building = new Building(b[2]); 40 | if(!events.containsKey(b[0])) events.put(b[0], new Event()); 41 | events.get(b[0]).starts.add(building); 42 | if(!events.containsKey(b[1])) events.put(b[1], new Event()); 43 | events.get(b[1]).ends.add(building); 44 | } 45 | 46 | ArrayList> ret = new ArrayList<>(); 47 | PriorityQueue curHeap = new PriorityQueue<>(); 48 | int curMaxHi = 0; 49 | int begin = 0; 50 | for(Map.Entry e: events.entrySet()) { 51 | for(Building building: e.getValue().starts) 52 | curHeap.add(building); 53 | for(Building building: e.getValue().ends) 54 | building.deleted = true; 55 | 56 | while(curHeap.size() > 0 && curHeap.peek().deleted) 57 | curHeap.remove(); 58 | 59 | int newHi = 0; 60 | if(curHeap.size() > 0) 61 | newHi = curHeap.peek().h; 62 | if(newHi != curMaxHi) { 63 | if(curMaxHi != 0) { 64 | ArrayList r = new ArrayList<>(); 65 | r.add(begin); r.add(e.getKey()); r.add(curMaxHi); 66 | ret.add(r); 67 | } 68 | begin = e.getKey(); 69 | curMaxHi = newHi; 70 | } 71 | } 72 | return ret; 73 | } 74 | public static void main(String[] args) { 75 | int[][] buildings = new int[][] { 76 | {1, 3, 3}, 77 | {2, 4, 4}, 78 | {5, 6, 1} 79 | }; 80 | List> expected = new ArrayList<>(); 81 | expected.add(Arrays.asList(1, 2, 3)); 82 | expected.add(Arrays.asList(2, 4, 4)); 83 | expected.add(Arrays.asList(5, 6, 1)); 84 | assert new Solution().buildingOutline(buildings).equals(expected); 85 | } 86 | } 87 | 88 | -------------------------------------------------------------------------------- /java/src/main/java/ContinuousSubarraySumII/Solution.java: -------------------------------------------------------------------------------- 1 | package ContinuousSubarraySumII; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * Created by Daniel on 19/06/15. 7 | */ 8 | public class Solution { 9 | class Sum { 10 | int sum; 11 | int i; 12 | int j; 13 | Sum(int sum, int i, int j) { 14 | this.sum = sum; 15 | this.i = i; 16 | this.j = j; 17 | } 18 | } 19 | 20 | /** 21 | * @param A an integer array 22 | * @return A list of integers includes the index of the first number and the index of the last number 23 | */ 24 | public ArrayList continuousSubarraySumII(int[] A) { 25 | Sum linearSum = this.linearMaxSum(A); 26 | Sum circularSum = this.circularMaxSum(A); 27 | ArrayList r = new ArrayList<>(); 28 | if(linearSum.sum>circularSum.sum) { 29 | r.add(linearSum.i); r.add(linearSum.j); 30 | } 31 | else { 32 | r.add(circularSum.i); r.add(circularSum.j); 33 | } 34 | return r; 35 | } 36 | 37 | Sum linearMaxSum(int[] A) { 38 | Sum ret = new Sum(A[0], 0, 0); 39 | int curMax = 0; 40 | int b = 0; 41 | for(int i=0; i ret.sum) { 44 | ret.sum = curMax; 45 | ret.i = b; ret.j = i; 46 | } 47 | if(curMax < 0) { 48 | b = i+1; 49 | curMax = 0; 50 | } 51 | } 52 | return ret; 53 | } 54 | 55 | Sum circularMaxSum(int[] A) { 56 | Sum[] fromRight = new Sum[A.length]; 57 | Sum[] fromLeft = new Sum[A.length]; 58 | Sum ret = new Sum(A[0], 0, 0); 59 | int curMax = 0; 60 | for(int i=0; i ret.sum) { 63 | ret = new Sum(curMax, 0, i); 64 | } 65 | fromLeft[i] = ret; 66 | } 67 | ret = new Sum(A[A.length-1], A.length-1, A.length-1); 68 | curMax = 0; 69 | for(int i=A.length-1; i>-1; i--) { 70 | curMax += A[i]; 71 | if(curMax > ret.sum) { 72 | ret = new Sum(curMax, i, A.length-1); 73 | } 74 | fromRight[i] = ret; 75 | } 76 | ret = new Sum(A[0], 0, 0); 77 | for(int i=1; iret.sum) { 81 | ret.sum = right.sum+left.sum; 82 | ret.i = right.i; 83 | ret.j = left.j; 84 | } 85 | } 86 | return ret; 87 | } 88 | 89 | public static void main(String[] args) { 90 | ArrayList expected = new ArrayList<>(); 91 | expected.add(4); expected.add(1); 92 | assert new Solution().continuousSubarraySumII(new int[]{3, 1, -100, -3, 4}).equals(expected); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /java/src/main/java/CountofSmallerNumberbeforeitself/Solution.java: -------------------------------------------------------------------------------- 1 | package CountofSmallerNumberbeforeitself; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by Daniel on 16/06/15. 9 | */ 10 | public class Solution { 11 | class Node { 12 | int val, count, countLeft; 13 | Node left, right; 14 | Node(int val) { 15 | this.val = val; 16 | } 17 | } 18 | 19 | class BST { 20 | Node root; 21 | 22 | void insert(Node root, int val) { 23 | if(this.root == null) { 24 | this.root = new Node(val); 25 | root = this.root; 26 | } 27 | assert root != null; 28 | 29 | if(root.val == val) 30 | root.count += 1; 31 | else if(val < root.val) { 32 | root.countLeft += 1; 33 | if(root.left == null) root.left = new Node(val); 34 | this.insert(root.left, val); 35 | } 36 | else { 37 | if(root.right == null) root.right = new Node(val); 38 | this.insert(root.right, val); 39 | } 40 | } 41 | 42 | int query(Node root, int val) { 43 | if(root == null) 44 | return 0; 45 | if(root.val < val) 46 | return root.count+root.countLeft+this.query(root.right, val); 47 | else if(root.val == val) 48 | return root.countLeft; 49 | else 50 | return this.query(root.left, val); 51 | } 52 | } 53 | /** 54 | * @param A: An integer array 55 | * @return: Count the number of element before this element 'ai' is 56 | * smaller than it and return count number array 57 | */ 58 | public ArrayList countOfSmallerNumberII(int[] A) { 59 | ArrayList ret = new ArrayList(); 60 | BST tree = new BST(); 61 | for(int a: A) { 62 | tree.insert(tree.root, a); 63 | ret.add(tree.query(tree.root, a)); 64 | } 65 | return ret; 66 | } 67 | 68 | public static void main(String[] args) { 69 | List expected = Arrays.asList(0, 1, 2, 3, 2); 70 | assert new Solution().countOfSmallerNumberII(new int[] {1, 2, 7, 8, 5}).equals(expected); 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /java/src/main/java/FourSum/Solution.java: -------------------------------------------------------------------------------- 1 | package FourSum; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * Created by Daniel on 19/06/15. 7 | */ 8 | public class Solution { 9 | /** 10 | * @param numbers : Give an array numbersbers of n integer 11 | * @param target : you need to find four elements that's sum of target 12 | * @return : Find all unique quadruplets in the array which gives the sum of 13 | * zero. 14 | */ 15 | public ArrayList> fourSum(int[] numbers, int target) { 16 | int n = numbers.length; 17 | ArrayList> ret = new ArrayList<>(); 18 | Set> retSet = new LinkedHashSet<>(); // normall HashSet cannot pass the OJ 19 | Map>> sum2index = new HashMap<>(); 20 | if(n<4) 21 | return ret; 22 | 23 | Arrays.sort(numbers); 24 | 25 | for(int i=0; i>()); 30 | sum2index.get(sum).add(Arrays.asList(i, j)); 31 | } 32 | } 33 | 34 | for(int i=0; i pair: sum2index.get(sumRemain)) { 39 | if(pair.get(0) > j) { 40 | retSet.add(new ArrayList<>(Arrays.asList( 41 | numbers[i], 42 | numbers[j], 43 | numbers[pair.get(0)], 44 | numbers[pair.get(1)] 45 | ))); 46 | } 47 | } 48 | } 49 | } 50 | } 51 | for(ArrayList elt: retSet) { 52 | ret.add(elt); 53 | } 54 | return ret; 55 | } 56 | 57 | public static void main(String[] args) { 58 | System.out.println(new Solution().fourSum(new int[]{1, 0, -1, 0, -2, 2}, 0)); 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /k Sum II.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given n unique integers, number k (1<=k<=n) and target. Find all possible k integers where their sum is target. 3 | 4 | Example 5 | Given [1,2,3,4], k=2, target=5, [1,4] and [2,3] are possible solutions. 6 | """ 7 | __author__ = 'Danyang' 8 | 9 | 10 | class Solution(object): 11 | def kSumII(self, A, k, target): 12 | """ 13 | brute force dfs 14 | Branch and prune 15 | 16 | :param A: An integer array. 17 | :param k: a positive integer (k <= length(A)) 18 | :param target: int 19 | :return: int 20 | """ 21 | ret = [] 22 | self.dfs(A, 0, k, [], target, ret) 23 | return ret 24 | 25 | def dfs(self, A, i, k, cur, remain, ret): 26 | """self.dfs(A, 0, k, [], target, ret)""" 27 | if len(cur) == k and remain == 0: 28 | ret.append(list(cur)) 29 | return 30 | 31 | if i >= len(A) or len(cur) > k or len(A)-i+len(cur) < k: 32 | return 33 | 34 | self.dfs(A, i+1, k, cur, remain, ret) 35 | cur.append(A[i]) 36 | self.dfs(A, i+1, k, cur, remain-A[i], ret) 37 | cur.pop() 38 | 39 | def dfs_array(self, A, k, cur, remain, ret): 40 | """ 41 | self.dfs_array(A, k, [], target, ret) 42 | """ 43 | if len(cur) == k and remain == 0: 44 | ret.append(list(cur)) 45 | 46 | if not A or len(cur) >= k or len(A)+len(cur) < k: 47 | return 48 | 49 | # save space 50 | num = A.pop(0) # possible optimized by stack 51 | 52 | self.dfs_array(A, k, cur, remain, ret) 53 | cur.append(num) 54 | self.dfs_array(A, k, cur, remain-num, ret) 55 | cur.pop() 56 | 57 | A.push(0, num) 58 | 59 | def dfs_stk(self, A, k, cur, remain, ret): 60 | """ 61 | self.dfs_stk(A[::-1], k, [], target, ret) 62 | since array insert takes O(n), speed up by using stack 63 | """ 64 | if len(cur) == k and remain == 0: 65 | ret.append(list(cur)) 66 | 67 | if not A or len(cur) >= k or len(A)+len(cur) < k: 68 | return 69 | 70 | # save space 71 | num = A.pop() 72 | 73 | self.dfs(A, k, cur, remain, ret) 74 | cur.append(num) 75 | self.dfs(A, k, cur, remain-num, ret) 76 | cur.pop() 77 | 78 | A.append(num) 79 | 80 | 81 | if __name__ == "__main__": 82 | print Solution().kSumII([1, 2, 3, 4], 2, 5) 83 | assert Solution().kSumII([1, 2, 3, 4], 2, 5) == [[3, 2], [1, 4]] -------------------------------------------------------------------------------- /k Sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given n distinct positive integers, integer k (k <= n) and a number target. 3 | 4 | Find k numbers where sum is target. Calculate how many solutions there are? 5 | 6 | Example 7 | Given [1,2,3,4], k=2, target=5. There are 2 solutions: 8 | 9 | [1,4] and [2,3], return 2. 10 | """ 11 | __author__ = 'Danyang' 12 | 13 | 14 | class Solution(object): 15 | def kSum(self, A, k, target): 16 | """ 17 | brute force O(n^k) 18 | 19 | :param A: An integer array. 20 | :param k: a positive integer (k <= length(A)) 21 | :param target: int 22 | :return: int 23 | """ 24 | return self.dp(A, k, target) 25 | 26 | def dp(self, A, K, target): 27 | """ 28 | DP: 29 | jCi = v 30 | 31 | f[i][j][v] = f[i-1][j-1][v-A[j-1]] + f[i][j-1][v] 32 | 33 | f[i][j][v] means the way of selecting i elements from the first j elements so that their sum equals to v 34 | j is the scanning pointer 35 | you can either select A[j-1] or not select A[j-1] 36 | 37 | O(n^2 k) 38 | 39 | :param A: 40 | :param K: 41 | :param target: 42 | :return: 43 | """ 44 | n = len(A) 45 | 46 | f = [[[0 for _ in xrange(target+1)] for _ in xrange(n+1)] for _ in xrange(K+1)] 47 | for ind, val in enumerate(A): 48 | if val <= target: 49 | for j in xrange(ind+1, n+1): # non-trivial 50 | f[1][j][val] = 1 51 | 52 | for i in xrange(2, K+1): 53 | for j in xrange(i, n+1): 54 | for v in xrange(1, target+1): 55 | f[i][j][v] = 0 56 | if v-A[j-1] >= 0: 57 | f[i][j][v] += f[i-1][j-1][v-A[j-1]] 58 | if j-1 >= i: 59 | f[i][j][v] += f[i][j-1][v] 60 | 61 | return f[K][n][target] 62 | 63 | def dfs_TLE(self, A, k, target, cur, ret): 64 | if len(cur) == k and sum(cur) == target: # possible to optimized 65 | ret[0] += 1 66 | 67 | if not A or len(cur) >= k: 68 | return 69 | 70 | # if save space, you need to do the clean up 71 | num = A.pop(0) 72 | self.dfs_TLE(A, k, target, cur, ret) 73 | A.push(0, num) 74 | 75 | num = A.pop(0) 76 | cur.append(num) 77 | self.dfs_TLE(A, k, target, cur, ret) 78 | cur.pop() 79 | A.push(0, num) 80 | 81 | def dfs_TLE_2(self, A, k, target, s, l, la, ret): 82 | """ 83 | Optimized version of dfs 84 | acceptable in k Sum II but TLE in k Sum 85 | """ 86 | if l == k and s == target: 87 | ret[0] += 1 88 | 89 | if not A or l >= k or la+l < k: 90 | return 91 | 92 | # if save space, you need to do the clean up 93 | num = A.pop(0) 94 | self.dfs_TLE_2(A, k, target, s, l, la-1, ret) 95 | self.dfs_TLE_2(A, k, target, s+num, l+1, la-1, ret) 96 | A.push(0, num) 97 | 98 | 99 | if __name__ == "__main__": 100 | assert Solution().kSum([1, 2, 3, 4], 2, 5) == 2 101 | assert Solution().kSum( 102 | [1, 3, 4, 5, 8, 10, 11, 12, 14, 17, 20, 22, 24, 25, 28, 30, 31, 34, 35, 37, 38, 40, 42, 44, 45, 48, 51, 54, 56, 103 | 59, 60, 61, 63, 66], 24, 842) == 453474 --------------------------------------------------------------------------------