├── README ├── dynamic ├── LCS.py ├── binary.py ├── frog.py ├── lcs_rec.py ├── longest_sequence.py ├── pairs.py ├── robber.py └── square.py ├── equilibrium_index.py ├── find_dup_ids.py ├── graph ├── Dijkstra.py ├── Edmonds-Karp.py ├── Ford-Fulkerson.py ├── __init__.py ├── flow_network.txt ├── graph.txt └── weighed_graph.txt ├── grep.py ├── move_average.py ├── problems ├── N-Queens │ └── brute_force.py ├── dup_element_in_array │ └── find_dup_elem.py ├── maximum_gap │ └── solution.py └── sudoku │ ├── easy50.txt │ ├── hardest.txt │ ├── sudoku_brute_force.py │ ├── sudoku_norvig.py │ └── top95.txt ├── sorting ├── 2011-10-19.00:29:17.pdf ├── __init__.py ├── algorithms.py ├── common.py ├── heapq.py └── main.py ├── spoj.pl ├── ADDRE.input ├── ADDRE.py ├── BANDW.input ├── BANDW.py ├── FCTRL.input ├── FCTRL.py ├── PRIME1.input ├── PRIME1.py └── a.c ├── strings ├── Boyer-Moore.py ├── Knuth-Morris-Pratt.py ├── near-words2.py ├── word-ladder.py └── word-ladder_v2.py ├── tail.origin.py ├── tail.py └── uniq_chars.py /README: -------------------------------------------------------------------------------- 1 | Track my python code snippets 2 | -------------------------------------------------------------------------------- /dynamic/LCS.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Longest Common Sequence, my not contigous 4 | 5 | import sys 6 | 7 | def LCS(str1, str2): 8 | row_num = len(str1) + 1 9 | col_num = len(str2) + 1 10 | 11 | # 2 dimension array to store LCS until a position 12 | # c[0] is all 0, c[x][0] is all 0 13 | c = [[0 for x in xrange(col_num)] for y in xrange(row_num)] 14 | 15 | # 2 dimension array to store the path to a LCS 16 | b = [[(0, 0) for x in xrange(col_num)] for y in xrange(row_num)] 17 | 18 | # Calculate all common sequences 19 | for i in xrange(1, row_num): 20 | for j in xrange(1, col_num): 21 | if str1[i - 1] == str2[j - 1]: 22 | c[i][j] = c[i - 1][j - 1] + 1 23 | b[i][j] = (i - 1, j - 1) 24 | else: 25 | if c[i - 1][j] >= c[i][j - 1]: 26 | c[i][j] = c[i - 1][j] 27 | b[i][j] = (i - 1, j) 28 | else: 29 | c[i][j] = c[i][j - 1] 30 | b[i][j] = (i, j - 1) 31 | 32 | # Get the longest one 33 | length = c[row_num - 1][col_num - 1] 34 | string = '' 35 | row = row_num - 1 36 | col = col_num -1 37 | 38 | while row > 0 or col > 0: 39 | new_row, new_col = b[row][col] 40 | if c[row][col] != c[new_row][new_col]: 41 | string += str1[row - 1] 42 | row = new_row 43 | col = new_col 44 | 45 | return length, string[::-1] 46 | 47 | 48 | if __name__ == '__main__': 49 | str1 = sys.argv[1] 50 | str2 = sys.argv[2] 51 | length, string= LCS(str1, str2) 52 | print length, string 53 | -------------------------------------------------------------------------------- /dynamic/binary.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Q. Given length n, number of binary sequences without consecutive 0s. 4 | # Requirement: 5 | # 1. Time complexity - O(n) 6 | # 7 | # i.e. give a length 4 binary, valid sequences are: 8 | # 1111, 0111, 1011, 1101, 1110, 0101,1010, 0110 9 | # 10 | 11 | 12 | def GetNonContinuousZero(size): 13 | start_with_zero = [0 for i in xrange(size + 1)] 14 | start_with_one = [0 for i in xrange(size + 1)] 15 | start_with_zero[1] = 1 16 | start_with_one[1] = 1 17 | for i in xrange(2, size + 1): 18 | start_with_zero[i] = start_with_one[i - 1] 19 | start_with_one[i] = start_with_one[i - 1] + start_with_zero[i - 1] 20 | return start_with_zero[size] + start_with_one[size] 21 | 22 | if __name__ == "__main__": 23 | for n in xrange(1,64): 24 | print 'Length: %s Non continuous 0: %s' % (n, GetNonContinuousZero(n)) 25 | -------------------------------------------------------------------------------- /dynamic/frog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Q. Maximum the number of flies the frog can eat 4 | # Limitations: the frog can only move right or down 5 | # Requirements: 6 | # 1. Time complexity - O(n^2) 7 | # 8 | # i.e. 9 | # ------------------------- 10 | # |frog | 2 | 0 | 1 | 11 | # ------------------------- 12 | # | 1 | 3 | 0 | 2 | 13 | # ------------------------- 14 | # | 2 | 1 | 1 | 2 | 15 | # ------------------------- 16 | # | 3 | 2 | 3 |exit | 17 | # ------------------------- 18 | # 19 | # The above square can be any size. 20 | # 21 | 22 | 23 | 24 | weight=[[0,2,0,1],[1,3,0,2],[2,1,1,2],[3,2,3,0]] 25 | 26 | def GetMaxFlies(weight): 27 | flies = {} 28 | for i in xrange(4): 29 | for j in xrange(4): 30 | if i == 0 and j == 0: 31 | flies[(i,j)] = 0 32 | elif i == 0: 33 | flies[(i,j)] = flies[(i, j - 1)] + weight[i][j] 34 | elif j == 0: 35 | flies[(i,j)] = flies[(i - 1, j)] + weight[i][j] 36 | else: 37 | flies[(i,j)] = max(flies[(i - 1, j)], flies[(i, j - 1)]) + weight[i][j] 38 | return flies[(3,3)] 39 | 40 | 41 | def GetMaxFliesAndPath(weight): 42 | flies = {} 43 | path = {(0, 0): None} 44 | height = len(weight) 45 | width = len(weight[0]) 46 | 47 | for i in xrange(height): 48 | for j in xrange(width): 49 | if i == 0 and j == 0: 50 | flies[(i,j)] = 0 51 | elif i == 0: 52 | flies[(i,j)] = flies[(i, j - 1)] + weight[i][j] 53 | path[(i, j)] = (i, j - 1) 54 | elif j == 0: 55 | flies[(i,j)] = flies[(i - 1, j)] + weight[i][j] 56 | path[(i, j)] = (i - 1, j) 57 | else: 58 | if flies[(i - 1, j)] > flies[(i, j - 1)]: 59 | flies[(i, j)] = flies[(i - 1, j)] + weight[i][j] 60 | path[(i, j)] = (i - 1, j) 61 | # elif flies[(i - 1, j)] < flies[(i, j - 1)]: 62 | else: 63 | flies[(i, j)] = flies[(i, j - 1)] + weight[i][j] 64 | path[(i, j)] = (i, j - 1) 65 | ## else: 66 | ## flies[(i, j)] = flies[(i - 1, j)] + weight[i][j] 67 | ## top_parent = path[(i - 1, j)] 68 | ## left_parent = path[(i, j - 1)] 69 | ## while (top_parent != None and left_parent != None): 70 | ## if flies[top_parent] > flies[left_parent]: 71 | ## path[(i, j)] = (i - 1, j) 72 | ## break 73 | ## else: 74 | ## path[(i, j)] = (i, j - 1) 75 | ## break 76 | ## top_parent = path[top_parent] 77 | ## left_parent = path[left_parent] 78 | 79 | return flies[(height - 1, width - 1)], path 80 | 81 | 82 | if __name__ == "__main__": 83 | print 'Board is:' 84 | for line in weight: 85 | print line 86 | max_flies = GetMaxFlies(weight) 87 | print 'Max flies number is: %s' % max_flies 88 | max_flies, path = GetMaxFliesAndPath(weight) 89 | print max_flies 90 | height = len(weight) 91 | width = len(weight[0]) 92 | 93 | print '(%s, %s) -> ' % (height -1, width - 1), 94 | parent = path[(height - 1, width - 1)] 95 | while (parent != None): 96 | print '(%s, %s) -> ' % parent, 97 | parent = path[parent] 98 | print 'None' 99 | -------------------------------------------------------------------------------- /dynamic/lcs_rec.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from functools import wraps 4 | 5 | def memo(func): 6 | cache = {} 7 | @wraps(func) 8 | def wrap(*args): 9 | if args not in cache: 10 | cache[args] = func(*args) 11 | return cache[args] 12 | return wrap 13 | 14 | 15 | # Recursive Solution 16 | def rec_lcs(a, b): 17 | @memo 18 | def L(i, j): 19 | if min(i, j) < 0: return '' 20 | if a[i] == b[j]: return L(i - 1, j - 1) + a[i] 21 | return max(L(i - 1, j), L(i, j - 1)) 22 | return L(len(a) - 1, len(b) - 1) 23 | 24 | 25 | # Iterative Solution 26 | def lcs_iter(a, b): 27 | n, m = len(a), len(b) 28 | pre, cur = [0] * (n + 1), [0] * (n + 1) 29 | for j in range(1, m + 1): 30 | pre, cur = cur, pre 31 | for i in range(1, n + 1): 32 | if a[i-1] == b[j-1]: 33 | cur[i] = pre[i-1] + 1 34 | else: 35 | cur[i] = max(pre[i], cur[i-1]) 36 | return cur[n] 37 | 38 | 39 | if __name__ == '__main__': 40 | str1 = 'abcdefg' 41 | str2 = 'xybhebg' 42 | print str1, str2, rec_lcs(str1, str2), lcs_iter(str1, str2) 43 | str1 = 'Starwalker' 44 | str2 = 'Starbuck' 45 | print str1, str2, rec_lcs(str1, str2), lcs_iter(str1, str2) 46 | -------------------------------------------------------------------------------- /dynamic/longest_sequence.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Q. Given a list of numbers, find out longest increasing sequence 4 | # Requirements: 5 | # 1. Time complexity - O(n) 6 | # 7 | # i.e. 8 | # input: 1 4 2 3 7 5 6 should give: 1 2 3 5 6 9 | # 10 | 11 | 12 | import bisect 13 | import random 14 | import sys 15 | 16 | 17 | # This function returns the length of longest increasing sequence. 18 | def lis(seq): 19 | end = [] 20 | for v in seq: 21 | idx = bisect.bisect(end, v) 22 | if idx == len(end): end.append(val) 23 | else: end[idx] = v 24 | return len(end) 25 | 26 | 27 | def GenerateList(size): 28 | return [random.randint(1, 500) for i in xrange(size)] 29 | 30 | 31 | def LongestSequence(numbers): 32 | length = len(numbers) 33 | result = [[] for i in xrange(length)] 34 | result[0].append(numbers[0]) 35 | 36 | for i in xrange(1, length): 37 | i_length = len(result[i]) 38 | temp_list = [] 39 | for j in xrange(i): 40 | if numbers[j] < numbers[i] and len(result[j]) > i_length: 41 | temp_list = result[j] 42 | # update i_length only got longer sequences 43 | i_length = len(result[j]) 44 | 45 | result[i].extend(temp_list) 46 | result[i].append(numbers[i]) 47 | 48 | # return result 49 | sequences = [result[0]] 50 | for sequence in result: 51 | if len(sequence) > len(sequences[0]): 52 | sequences = [sequence] 53 | elif len(sequence) == len(sequences[0]): 54 | sequences.append(sequence) 55 | return sequences 56 | 57 | 58 | if __name__ == "__main__": 59 | numbers1 = [1,4,2,3,7,5,6,8,5,9,11,10,12] 60 | numbers2 = [20,18,22,26,22,24,30,25,32,26,1,3,2,4,2,5,7,6,8,9,10] 61 | size = int(sys.argv[1]) 62 | l = GenerateList(size) 63 | print l 64 | results = LongestSequence(l) 65 | for line in results: 66 | print line 67 | n3=[180, 359, 226, 434, 251, 116, 33, 97, 366, 169, 289, 193, 120, 215, 281, 452, 247, 6, 230, 107] 68 | results = LongestSequence(n3) 69 | for line in results: 70 | print line 71 | -------------------------------------------------------------------------------- /dynamic/pairs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Q. Find the number of correct parenthesis sequence of length 2*n 4 | # Requirements: 5 | # 1. Time complexity - O(n^2) 6 | # 7 | # i.e. 8 | # length 2*3, number is 5: ()()(), (())(), ()(()), (()()), ((())) 9 | # 10 | 11 | 12 | import copy 13 | 14 | 15 | # This is not the correct answer 16 | # The result has duplicated combinations 17 | def RecursiveCalculate(left, right): 18 | # copy.copy only copies direct object reference, not second level 19 | left_copy = copy.deepcopy(left) 20 | first = left_copy.pop(0) 21 | if first[1] == right: 22 | #first[1] = ')' * right 23 | #return [first] 24 | return [['(' + ')' * right]] 25 | return_list = [] 26 | for level in xrange(1, first[1] + 1): 27 | closed_first = RecursiveCalculate(left_copy, right - first[1]) 28 | for item in closed_first: 29 | #return_list.append([first[0], ')'] + item) 30 | return_list.append(['(' + ')' * first[1]] + item) 31 | left_copy[0][1] = left_copy[0][1] + first[1] 32 | opened_first = RecursiveCalculate(left_copy, right) 33 | for item in opened_first: 34 | return_list.append(['('] + item) 35 | #return_list.append([[first[0], '']] + item) 36 | return return_list 37 | 38 | 39 | def GetPairs(size): 40 | left = [['(', 1] for i in xrange(size / 2)] 41 | right = size / 2 42 | return RecursiveCalculate(left, right) 43 | 44 | if __name__ == "__main__": 45 | for n in xrange(2, 24, 1): 46 | pairs = GetPairs(n * 2) 47 | print 'Valid combinations for %s pairs is: %s' % (n, len(pairs)) 48 | #for pair in pairs: 49 | # print ''.join(pair) 50 | -------------------------------------------------------------------------------- /dynamic/robber.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Q. A robber in a jewelry shop, he can only carry 7 pounds items 4 | # Each valuable item has a value and weight, (value, weight) 5 | # How could he maximum the value of items he will carry? 6 | # 7 | # i.e. 8 | # 9 | # items: (5, 2), (7, 3), (4, 2), (3, 4). 10 | # 11 | 12 | 13 | INFINITY = -100000 14 | 15 | def GetMax(items, weight): 16 | l = (weight + 1) * [INFINITY] 17 | l[0] = 0 18 | max_cost = [] 19 | for cost, weigh in items: 20 | nl = l[:] 21 | for i in xrange(weight + 1): 22 | if l[i] > INFINITY and i + weigh <= weight: 23 | new_cost = l[i] + cost 24 | if nl[i + weigh] < new_cost: 25 | nl[i + weigh] = new_cost 26 | max_cost.append(nl) 27 | l = nl 28 | return max_cost 29 | 30 | 31 | def GetMaxWithPath(items, weight): 32 | l = [] 33 | for i in xrange(weight + 1): 34 | l.append([INFINITY, []]) 35 | l[0][0] = 0 36 | max_cost = [] 37 | items_index = 0 38 | for cost, weigh in items: 39 | nl = l[:] 40 | for i in xrange(weight + 1): 41 | if l[i][0] > INFINITY and i + weigh <= weight: 42 | new_cost = l[i][0] + cost 43 | if nl[i + weigh][0] < new_cost: 44 | nl[i + weigh][1].append((cost, weigh)) 45 | max_cost.append(nl) 46 | l = nl 47 | return max_cost 48 | 49 | 50 | if __name__ == "__main__": 51 | items = [(5, 2), (7, 3), (4, 2), (3, 4)] 52 | weight = 7 53 | max_cost = GetMaxWithPath(items, weight) 54 | for line in max_cost: 55 | print line 56 | -------------------------------------------------------------------------------- /dynamic/square.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Q1. Given a array, request (a,b), give sum of [a:b] 4 | # Requirements: 5 | # 1. Time complexity -O(1) 6 | # 2. Space complexity - O(1) # or no extra space 7 | # 3. Data size - 10^7 8 | # 9 | # Q2. Given a n*n square, request ((a,b), (c,d)), give sum of sub square 10 | # Requirements: 11 | # 1. Time complexity -O(1) 12 | # 2. Space complexity - O(1) # or no extra space 13 | # 3. Data size - 10^7*10^7 14 | # 15 | 16 | 17 | def ArraySum(array): 18 | for i in xrange(1, len(array)): 19 | array[i] = array[i] + array[i-1] 20 | 21 | 22 | def QuerySub(start, end): 23 | if start == 0: 24 | return array[end] 25 | else: 26 | return array[end] - array[start - 1] 27 | 28 | 29 | def SquareSum(square): 30 | height = len(square) 31 | width = len(square[0]) 32 | for i in xrange(height): 33 | for j in xrange(1, width): 34 | square[i][j] = square[i][j] + square[i][j-1] 35 | for j in xrange(width): 36 | if i == 0: 37 | break 38 | else: 39 | square[i][j] = square[i - 1][j] + square[i][j] 40 | 41 | 42 | def QuerySubSquare(start, end): 43 | a, b = start 44 | d, c = end 45 | 46 | if a == 0 and b == 0: 47 | return square[d][c] 48 | elif a == 0: 49 | return square[d][c] - square[d][b - 1] + square[a][b - 1] 50 | elif b == 0: 51 | return square[d][c] - square[a - 1][c] + square[a - 1][b] 52 | else: 53 | return square[d][c] - square[a - 1][c] - square[d][b - 1] + square[a - 1][b - 1] 54 | 55 | if __name__ == "__main__": 56 | array = [1,2,3,4,5,6,7,8,9,10] 57 | print array 58 | ArraySum(array) 59 | print array 60 | sum = QuerySub(2,5) 61 | print 'QuerySub(2,5) = %s' % sum 62 | sum = QuerySub(0,5) 63 | print 'QuerySub(0,5) = %s' % sum 64 | sum = QuerySub(0,9) 65 | print 'QuerySub(0,9) = %s' % sum 66 | 67 | square = [ 68 | [1,2,3,4,5,6], 69 | [2,3,4,5,6,7], 70 | [3,4,5,6,7,8], 71 | [4,5,6,7,8,9], 72 | [5,6,7,8,9,0]] 73 | for line in square: 74 | print line 75 | SquareSum(square) 76 | for line in square: 77 | print line 78 | sum = QuerySubSquare((1, 1), (2, 3)) 79 | print 'QuerySubSquare((1, 1), (2, 3)) = %s' % sum 80 | sum = QuerySubSquare((2, 1), (4, 3)) 81 | print 'QuerySubSquare((2, 1), (4, 3)) = %s' % sum 82 | sum = QuerySubSquare((0, 0), (1, 1)) 83 | print 'QuerySubSquare((0, 0), (1, 1)) = %s' % sum 84 | sum = QuerySubSquare((0, 0), (4, 5)) 85 | print 'QuerySubSquare((0, 0), (5, 5)) = %s' % sum 86 | sum = QuerySubSquare((1, 0), (2, 3)) 87 | print 'QuerySubSquare((1, 0), (2, 3)) = %s' % sum 88 | sum = QuerySubSquare((0, 1), (2, 3)) 89 | print 'QuerySubSquare((0, 1), (2, 3)) = %s' % sum 90 | -------------------------------------------------------------------------------- /equilibrium_index.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | def GetEquilibriumIndex(l): 5 | s = sum(l) 6 | ls = 0 7 | results = [] 8 | for i in xrange(len(l)): 9 | s -= l[i] 10 | if ls == s: 11 | results.append(i) 12 | ls += l[i] 13 | 14 | return results 15 | 16 | if __name__ == '__main__': 17 | l = [-7, 1, 5, 2, -4, 3, 0] 18 | results = GetEquilibriumIndex(l) 19 | for result in results: 20 | print result 21 | -------------------------------------------------------------------------------- /find_dup_ids.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | 5 | def find_dup_id(path): 6 | dup_id = {} 7 | f = open(path, 'r') 8 | for line in f.readlines(): 9 | user, pwd, uid = line.split(':')[0:3] 10 | if uid not in dup_id: 11 | dup_id[uid] = [user] 12 | else: 13 | dup_id[uid].append(user) 14 | 15 | for uid, users in dup_id.iteritems(): 16 | if len(users) > 1: 17 | print uid, users 18 | 19 | 20 | if __name__ == '__main__': 21 | find_dup_id(sys.argv[1]) 22 | -------------------------------------------------------------------------------- /graph/Dijkstra.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Q. find out shortest path from a Node to any other Nodes 4 | # Requirements: 5 | # 1. no negative weights between two nodes 6 | # 2. Dijkstra algorithm (http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) 7 | # 8 | 9 | 10 | import sys 11 | 12 | 13 | parents = {} 14 | vertices = [] 15 | visited = set() 16 | 17 | def ReadGraphMatrix(file_name): 18 | graph = {} 19 | file_object = open(file_name, "r") 20 | for line in file_object.readlines(): 21 | vertex, matrix = line.rstrip().split(':') 22 | graph[vertex] = matrix.split(',') 23 | return graph 24 | 25 | 26 | def ReadGraph(file_name): 27 | graph = {} 28 | weight = {} 29 | file_object = open(file_name, "r") 30 | for line in file_object.readlines(): 31 | vertex, neighbors_weight = line.rstrip().split(':') 32 | vertex = int(vertex) 33 | graph[vertex] = [] 34 | weight[vertex] = {} 35 | for i in neighbors_weight.split(','): 36 | neighbor, weigh = i.split('!') 37 | neighbor = int(neighbor) 38 | graph[vertex].append(neighbor) 39 | weight[vertex][neighbor] = int(weigh) 40 | return graph, weight 41 | 42 | 43 | def D(s, graph, weight): 44 | visited = set() 45 | parents = {s:None} 46 | dist = {s:0} 47 | 48 | 49 | while True: 50 | min_node = None 51 | min_dist = 0 52 | for c in graph: 53 | if c not in visited and (min_node is None or 54 | min_dist > dist.setdefault(c, 100000)): 55 | min_node = c 56 | min_dist = dist[c] 57 | 58 | if min_node is None: 59 | break 60 | visited.add(min_node) 61 | for i in graph[min_node]: 62 | if i not in dist: 63 | dist[i] = min_dist + weight[min_node][i] 64 | parents[i] = min_node 65 | elif dist[i] > min_dist + weight[min_node][i]: 66 | dist[i] = min_dist + weight[min_node][i] 67 | parents[i] = min_node 68 | 69 | return parents, dist 70 | 71 | 72 | def PrintPathTo(node, parents): 73 | path = [] 74 | while parents[node] != None: 75 | path.append(node) 76 | node = parents[node] 77 | path.append(0) 78 | path.reverse() 79 | return path 80 | 81 | 82 | def DFS(root, graph): 83 | visited.add(root) 84 | pass 85 | 86 | 87 | if __name__ == "__main__": 88 | graph,weight = ReadGraph(sys.argv[1]) # use weighed_graph.txt 89 | node = int(sys.argv[2]) 90 | print 'graph: %s' % graph 91 | print 'Weight: %s' %weight 92 | parents,dist = D(0, graph, weight) 93 | path = PrintPathTo(node, parents) 94 | print 'Path from 0 to %s: %s' % (sys.argv[2], path) 95 | -------------------------------------------------------------------------------- /graph/Edmonds-Karp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # It's to find out max flow in a flow network 4 | # It's similar to Ford-Fulkerson algorithm, 5 | # but defines search order for augmenting path 6 | # The path found must be a shortest path that has available capacity. 7 | # http://en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm 8 | # 9 | 10 | import decimal 11 | import sys 12 | 13 | def EdmondsKarp(capacity, neighbors, start, end): 14 | flow = 0 15 | length = len(capacity) 16 | flows = [[0 for i in range(length)] for j in range(length)] 17 | while True: 18 | max, parent = BreadthFirstSearch(capacity, neighbors, flows, start, end) 19 | print 'max:%s' % max 20 | print parent 21 | if max == 0: 22 | break 23 | flow = flow + max 24 | v = end 25 | while v != start: 26 | u = parent[v] 27 | flows[u][v] = flows[u][v] + max 28 | flows[v][u] = flows[v][u] - max 29 | v = u 30 | return (flow, flows) 31 | 32 | 33 | 34 | def BreadthFirstSearch(capacity, neighbors, flows, start, end): 35 | length = len(capacity) 36 | parents = [-1 for i in xrange(length)] # parent table 37 | parents[start] = -2 # make sure source is not rediscovered 38 | M = [0 for i in xrange(length)] # Capacity of path to vertex i 39 | M[start] = decimal.Decimal('Infinity') # this is necessary! 40 | 41 | queue = [] 42 | queue.append(start) 43 | while queue: 44 | u = queue.pop(0) 45 | for v in neighbors[u]: 46 | # if there is available capacity and v is is not seen before in search 47 | if capacity[u][v] - flows[u][v] > 0 and parents[v] == -1: 48 | parents[v] = u 49 | # it will work because at the beginning M[u] is Infinity 50 | M[v] = min(M[u], capacity[u][v] - flows[u][v]) # try to get smallest 51 | if v != end: 52 | queue.append(v) 53 | else: 54 | return M[end], parents 55 | return 0, parents 56 | 57 | 58 | def ParseGraph(file): 59 | file_object = open(file, "r") 60 | capacity = [] 61 | neighbors = {} # neighbors include reverse direction neighbors 62 | for line in file_object.readlines(): 63 | capacity.append([int(i) for i in line.split(',')]) 64 | for vertex in xrange(len(capacity)): 65 | neighbors[vertex] = [] 66 | for vertex, flows in enumerate(capacity): 67 | for neighbor, flow in enumerate(flows): 68 | if flow > 0: 69 | neighbors[vertex].append(neighbor) 70 | neighbors[neighbor].append(vertex) # reverse path may be used 71 | return capacity, neighbors 72 | 73 | 74 | if __name__ == "__main__": 75 | file_name = sys.argv[1] # use file flow_network.txt 76 | capacity, neighbors = ParseGraph(file_name) 77 | for line in capacity: 78 | print line 79 | print neighbors 80 | flow, flows = EdmondsKarp(capacity, neighbors, 0, 6) 81 | print 'Max flow: %s' % flow 82 | print 'Flow matrix:' 83 | for line in flows: 84 | print line 85 | -------------------------------------------------------------------------------- /graph/Ford-Fulkerson.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # http://en.wikipedia.org/wiki/Ford-Fulkerson_algorithm 4 | # Ford-Fulkerson algorithm computes max flow in a flow network. 5 | # 6 | 7 | 8 | class Edge(object): 9 | def __init__(self, u, v, w): 10 | self.source = u 11 | self.target = v 12 | self.capacity = w 13 | 14 | def __repr__(self): 15 | return "%s->%s:%s" % (self.source, self.target, self.capacity) 16 | 17 | 18 | class FlowNetwork(object): 19 | def __init__(self): 20 | self.adj = {} 21 | self.flow = {} 22 | 23 | def AddVertex(self, vertex): 24 | self.adj[vertex] = [] 25 | 26 | def GetEdges(self, v): 27 | return self.adj[v] 28 | 29 | def AddEdge(self, u, v, w = 0): 30 | if u == v: 31 | raise ValueError("u == v") 32 | edge = Edge(u, v, w) 33 | redge = Edge(v, u, 0) 34 | edge.redge = redge 35 | redge.redge = edge 36 | self.adj[u].append(edge) 37 | self.adj[v].append(redge) 38 | # Intialize all flows to zero 39 | self.flow[edge] = 0 40 | self.flow[redge] = 0 41 | 42 | def FindPath(self, source, target, path): 43 | if source == target: 44 | return path 45 | for edge in self.GetEdges(source): 46 | residual = edge.capacity - self.flow[edge] 47 | if residual > 0 and not (edge, residual) in path: 48 | result = self.FindPath(edge.target, target, path + [(edge, residual)]) 49 | if result != None: 50 | return result 51 | 52 | def MaxFlow(self, source, target): 53 | path = self.FindPath(source, target, []) 54 | print 'path after enter MaxFlow: %s' % path 55 | for key in self.flow: 56 | print '%s:%s' % (key,self.flow[key]) 57 | print '-' * 20 58 | while path != None: 59 | flow = min(res for edge, res in path) 60 | for edge, res in path: 61 | self.flow[edge] += flow 62 | self.flow[edge.redge] -= flow 63 | for key in self.flow: 64 | print '%s:%s' % (key,self.flow[key]) 65 | path = self.FindPath(source, target, []) 66 | print 'path inside of while loop: %s' % path 67 | for key in self.flow: 68 | print '%s:%s' % (key,self.flow[key]) 69 | return sum(self.flow[edge] for edge in self.GetEdges(source)) 70 | 71 | 72 | if __name__ == "__main__": 73 | g = FlowNetwork() 74 | map(g.AddVertex, ['s', 'o', 'p', 'q', 'r', 't']) 75 | g.AddEdge('s', 'o', 5) 76 | g.AddEdge('s', 'p', 3) 77 | g.AddEdge('o', 'p', 2) 78 | g.AddEdge('o', 'q', 3) 79 | g.AddEdge('p', 'r', 4) 80 | g.AddEdge('r', 't', 3) 81 | g.AddEdge('q', 'r', 4) 82 | g.AddEdge('q', 't', 2) 83 | print g.MaxFlow('s', 't') 84 | -------------------------------------------------------------------------------- /graph/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigbighd604/Python/0e65672ad7bcd9e60d1f43837156ae94edb41027/graph/__init__.py -------------------------------------------------------------------------------- /graph/flow_network.txt: -------------------------------------------------------------------------------- 1 | 0,3,0,3,0,0,0 2 | 0,0,4,0,0,0,0 3 | 3,0,0,1,2,0,0 4 | 0,0,0,0,2,6,0 5 | 0,1,0,0,0,0,1 6 | 0,0,0,0,0,0,9 7 | 0,0,0,0,0,0,0 8 | -------------------------------------------------------------------------------- /graph/graph.txt: -------------------------------------------------------------------------------- 1 | 0:0,1,0,0,1,1,0,0 2 | 1:0,1,1,1,0,0,0,0 3 | 2:0,0,0,1,0,0,0,0 4 | 3:0,0,0,0,0,0,0,0 5 | 4:0,0,0,0,0,0,0,0 6 | 5:0,0,0,0,0,0,1,0 7 | 6:0,0,0,0,0,0,0,1 8 | 7:0,0,0,0,0,1,1,0 9 | -------------------------------------------------------------------------------- /graph/weighed_graph.txt: -------------------------------------------------------------------------------- 1 | 0:1!1,2!2 2 | 1:3!5 3 | 2:3!1,4!3 4 | 3:5!1 5 | 4:6!1 6 | 5:6!1 7 | 6:4!1 8 | -------------------------------------------------------------------------------- /grep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Copyright 2011 Google Inc. All Rights Reserved. 3 | 4 | """ 5 | Example 'grep' for the C03 exercis for SRE-U 2011. 6 | 7 | This implements all flags, and tries to match several idiosyncrasies of GNU 8 | grep. 9 | 10 | This is purposely not a good example of how to write code, but has a few nice 11 | tricks in places. 12 | """ 13 | 14 | __author__ = 'bbrazil@google.com (Brian Brazil)' 15 | 16 | import collections 17 | import getopt 18 | import itertools 19 | import re 20 | import sys 21 | import os 22 | 23 | class Args(object): pass 24 | 25 | 26 | def ParseArgs(argv): 27 | args = Args() 28 | option_args = 'ABf' 29 | nonoption_args = 'ncwlLqrvxhHiFoz' 30 | for arg in nonoption_args: 31 | setattr(args, arg, False) 32 | 33 | args.A = 0 34 | args.B = 0 35 | args.f = False 36 | 37 | opts, remainder = getopt.getopt( 38 | argv[1:], nonoption_args + ''.join([x + ':' for x in option_args])) 39 | 40 | for o, v in opts: 41 | o = o[1:] 42 | if o not in option_args: 43 | v = True 44 | elif o in 'AB': 45 | v = int(v) 46 | setattr(args, o, v) 47 | if o == 'h': 48 | args.H = False 49 | elif o == 'H': 50 | args.h = False 51 | 52 | if o == 'l': 53 | args.L = False 54 | elif o == 'L': 55 | args.l = False 56 | 57 | if args.r: 58 | args.h = False 59 | args.H = True 60 | 61 | if args.L or args.l: 62 | args.c = False 63 | args.o = False 64 | 65 | if args.o: 66 | args.A = 0 67 | args.B = 0 68 | 69 | return args, remainder 70 | 71 | 72 | def GenerateFiles(paths, args): 73 | if args.r: 74 | for p in paths: 75 | for root, _, files in os.walk(p): 76 | for f in files: 77 | fullpath = os.path.join(root, f) 78 | if os.path.isfile(fullpath): 79 | yield fullpath 80 | else: 81 | for f in paths: 82 | yield f 83 | 84 | 85 | def AtLeastTwoFiles(filegen): 86 | first = None 87 | second = None 88 | try: 89 | first = filegen.next() 90 | second = filegen.next() 91 | except StopIteration: 92 | pass 93 | 94 | filegen = itertools.chain( 95 | [x for x in [first, second] if x is not None], filegen) 96 | return filegen, second is not None 97 | 98 | 99 | def Match(line, patterns, args): 100 | if args.F: 101 | if args.i: 102 | line = line.lower() 103 | if args.x: 104 | matcher = lambda a, b: a == b 105 | else: 106 | matcher = lambda a, b: a in b 107 | for pattern in patterns: 108 | if matcher(pattern, line): 109 | if not args.v: 110 | return True, pattern 111 | else: 112 | if args.v: 113 | return True, None 114 | else: 115 | for pattern in patterns: 116 | match = pattern.search(line) 117 | if match: 118 | if not args.v: 119 | return True, match.group(0) 120 | else: 121 | if args.v: 122 | return True, None 123 | return False, None 124 | 125 | 126 | def PrintLine(filename, line_no, text, context, args): 127 | if args.l or args.L or args.q or args.c: 128 | return 129 | output = [] 130 | if args.H: 131 | output.append(filename) 132 | if args.n: 133 | output.append(str(line_no + 1)) 134 | output.append(text) 135 | if context: 136 | sys.stdout.write('-'.join(output)) 137 | else: 138 | sys.stdout.write(':'.join(output)) 139 | 140 | 141 | def GenLines(fd, args): 142 | if args.z: 143 | while True: 144 | line = '' 145 | buf = fd.read(8192) 146 | if not buf: 147 | if line: 148 | yield buf + '\0' 149 | return 150 | while True: 151 | pos = buf.find('\0') 152 | if pos == -1: 153 | line += buf 154 | break 155 | else: 156 | yield line + buf[:pos + 1] 157 | buf = buf[pos + 1:] 158 | line = '' 159 | else: 160 | for line in fd: 161 | if not line.endswith('\n'): 162 | line += '\n' 163 | yield line 164 | 165 | 166 | def main(argv): 167 | args, argv = ParseArgs(argv) 168 | 169 | patterns = [] 170 | if args.f: 171 | patterns.extend([p[:-1] for p in open(args.f)]) 172 | else: 173 | patterns.append(argv.pop(0)) 174 | 175 | if not argv: 176 | argv = ['-'] 177 | 178 | filegen = GenerateFiles(argv, args) 179 | 180 | filegen, two_plus_files = AtLeastTwoFiles(filegen) 181 | if two_plus_files: 182 | if not args.h: 183 | args.h = False 184 | args.H = True 185 | else: 186 | if not args.H: 187 | args.h = True 188 | args.H = False 189 | 190 | if not args.F: 191 | if args.x: 192 | patterns = ["^(%s)$" % p for p in patterns] 193 | patterns = [re.compile(p, re.I if args.i else 0) for p in patterns] 194 | else: 195 | patterns = list(itertools.chain(*[p.split("\n") for p in patterns])) 196 | if args.i: 197 | patterns = [p.lower() for p in patterns] 198 | 199 | trailing = 0 200 | leading = collections.deque(maxlen=args.B) 201 | had_a_match = False 202 | 203 | for filename in filegen: 204 | if filename == '-': 205 | filename = '/dev/stdin' 206 | with open(filename, 'rb' if args.z else 'r') as f: 207 | lines_matched = 0 208 | for line_no, line in enumerate(GenLines(f, args)): 209 | if args.w: 210 | parts = re.split("[^\w_]+", line[:-1]) 211 | else: 212 | parts = [line[:-1]] 213 | 214 | matches_found = [] 215 | for part in parts: 216 | match, text = Match(part, patterns, args) 217 | if match: 218 | matches_found.append(text) 219 | if matches_found: 220 | lines_matched += 1 221 | if args.o: 222 | for mf in matches_found: 223 | PrintLine(filename, line_no, mf + '\n', False, args) 224 | else: 225 | if leading and not args.q and had_a_match: 226 | print '--' 227 | for ln, t in leading: 228 | PrintLine(filename, ln, t, True, args) 229 | leading.clear() 230 | PrintLine(filename, line_no, line, False, args) 231 | trailing = args.A 232 | had_a_match = True 233 | else: 234 | leading.append((line_no, line)) 235 | if trailing: 236 | PrintLine(filename, line_no, line, True, args) 237 | trailing -= 1 238 | if not args.q: 239 | if args.l and lines_matched: 240 | print filename 241 | elif args.L and not lines_matched: 242 | print filename 243 | elif args.c: 244 | if args.H: 245 | print "%s:%s" % (filename, lines_matched) 246 | else: 247 | print lines_matched 248 | 249 | return 0 if had_a_match else 1 250 | 251 | 252 | if __name__ == '__main__': 253 | os.sys.exit(main(sys.argv)) 254 | -------------------------------------------------------------------------------- /move_average.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import collections 4 | import itertools 5 | 6 | 7 | def GetMoveAverage2(l, n): 8 | it = iter(l) 9 | d = collections.deque(itertools.islice(it, n-1)) 10 | d.appendleft(0) 11 | s = sum(d) 12 | for elem in it: 13 | s += elem - d.popleft() 14 | d.append(elem) 15 | yield s / float(n) 16 | 17 | 18 | def GetMoveAverage(l, size): 19 | length = len(l) 20 | 21 | s = sum(l[:size]) 22 | i = size 23 | 24 | while i < length: 25 | yield s / size 26 | s += l[i] - l[i - size] 27 | i += 1 28 | # last while iteration will cause i == length 29 | # But still need output the average number 30 | yield s / size 31 | 32 | if __name__ == '__main__': 33 | l = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100] 34 | results = GetMoveAverage(l, 4) 35 | for result in results: 36 | print result 37 | results = GetMoveAverage2(l, 4) 38 | for result in results: 39 | print result 40 | -------------------------------------------------------------------------------- /problems/N-Queens/brute_force.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # http://en.wikipedia.org/wiki/Eight_queens_puzzle 4 | # 5 | 6 | from itertools import permutations 7 | 8 | n = 8 9 | cols = range(n) 10 | results = [] 11 | 12 | for vec in permutations(cols): 13 | # check diagonal attack, for col position, m and n: 14 | # abs(vec[m] - vec[n]) == abs(m - n) if there is diagonal attack 15 | # means: 16 | # a. vec[m] - vec[n] = m - n ==> vec[m] - m == vec[n] - n 17 | # b. vec[m] - vec[n] = n - m ==> vec[m] + m == vec[n] + n 18 | # if exists one pair (m, n), then there is diagonal attack. 19 | if (n == len(set(vec[i]+i for i in cols)) == 20 | len(set(vec[i]-i for i in cols))): 21 | results.append(vec) 22 | 23 | 24 | print results 25 | -------------------------------------------------------------------------------- /problems/dup_element_in_array/find_dup_elem.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | #Suppose you have an array of 1001 integers. The integers are in random order, 4 | # but you know each of the integers is between 1 and 1000 (inclusive). 5 | # In addition, each number appears only once in the array, except for 6 | # one number, which occurs twice. Assume that you can access each element 7 | # of the array only once. Describe an algorithm to find the repeated number. 8 | # If you used auxiliary storage in your algorithm, can you find an algorithm 9 | # that does not require it? 10 | 11 | import random 12 | import sys 13 | import timeit 14 | 15 | class FindDuplicate(object): 16 | array = None 17 | 18 | @classmethod 19 | def GenArray(cls, length): 20 | if cls.array: 21 | return cls.array 22 | else: 23 | array = range(1,length + 1) 24 | dup = random.randint(1, length) 25 | print 'Dup num generated: %s' % dup 26 | array.append(dup) 27 | random.shuffle(array) 28 | cls.array = array 29 | return cls.array 30 | 31 | # By exploiting the following fact: 32 | # a ^ a = 0 33 | # 0 ^ a = a 34 | # This XorFind use one extra storage space. 35 | # In place modification of array uses no extra space. 36 | @classmethod 37 | def XorFind(cls, info=False): 38 | found = 0 39 | for i, item in enumerate(cls.array): 40 | found = found ^ item ^ i 41 | # An alternative: 42 | #for i in xrange(1, length + 2): 43 | # found = found ^ array[i-1] ^ (i - 1) 44 | if info: 45 | print 'Dup num founded (Xor): %s' % found 46 | 47 | # May overflow when dealing with huge array. 48 | @classmethod 49 | def SumFind(cls, info=False): 50 | length = len(cls.array) 51 | expect_sum = (1 + length - 1) * (length - 1) / 2 52 | real_sum = reduce(lambda x, y : x + y, cls.array) 53 | if info: 54 | print 'Dup num founded (Sum): %s' % (real_sum - expect_sum) 55 | 56 | @classmethod 57 | def AbsFind(cls, info=False): 58 | array = cls.array[:] 59 | for i in xrange(len(array)): 60 | if array[abs(array[i])] > 0: 61 | array[abs(array[i])] = - array[abs(array[i])] 62 | else: 63 | if info: 64 | print 'Dup num found (Abs): %s' % abs(array[i]) 65 | break 66 | 67 | if __name__ == '__main__': 68 | length = int(sys.argv[1]) 69 | num = int(sys.argv[2]) 70 | FindDuplicate.GenArray(length) 71 | FindDuplicate.XorFind(info=True) 72 | FindDuplicate.SumFind(info=True) 73 | FindDuplicate.AbsFind(info=True) 74 | print 'Xor: %s' % timeit.timeit(FindDuplicate.XorFind, number = num) 75 | print 'Sum: %s' % timeit.timeit(FindDuplicate.SumFind, number = num) 76 | print 'Abs: %s' % timeit.timeit(FindDuplicate.AbsFind, number = num) 77 | -------------------------------------------------------------------------------- /problems/maximum_gap/solution.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | class Solution(object): 4 | # Radix sort 5 | def MaxGap(self, nums): 6 | if len(nums) < 2: 7 | return 0 8 | num_strs = [] 9 | max_size = 1 10 | for s in nums: 11 | num_strs.append(str(s)[::-1]) 12 | max_size = max(max_size, len(str(s))) 13 | print num_strs 14 | for i in range(max_size): 15 | buckets = [[] for j in range(10)] 16 | for s in num_strs: 17 | # Move smaller number to left most bucket 18 | if len(s) <= i: 19 | buckets[0].append(s) 20 | else: 21 | buckets[int(s[i])].append(s) 22 | print buckets 23 | num_strs = [] 24 | for j in range(10): 25 | num_strs.extend(buckets[j]) 26 | nums = [int(x[::-1]) for x in num_strs] 27 | print nums 28 | max_gap = 0 29 | for x in range(len(nums) - 1): 30 | max_gap = max(max_gap, nums[x+1] - nums[x]) 31 | 32 | return max_gap 33 | 34 | 35 | 36 | l1 = [123, 78, 457, 234, 345, 320] 37 | 38 | if __name__ == '__main__': 39 | s = Solution() 40 | print s.MaxGap(l1) 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /problems/sudoku/easy50.txt: -------------------------------------------------------------------------------- 1 | 003020600 2 | 900305001 3 | 001806400 4 | 008102900 5 | 700000008 6 | 006708200 7 | 002609500 8 | 800203009 9 | 005010300 10 | ======== 11 | 200080300 12 | 060070084 13 | 030500209 14 | 000105408 15 | 000000000 16 | 402706000 17 | 301007040 18 | 720040060 19 | 004010003 20 | ======== 21 | 000000907 22 | 000420180 23 | 000705026 24 | 100904000 25 | 050000040 26 | 000507009 27 | 920108000 28 | 034059000 29 | 507000000 30 | ======== 31 | 030050040 32 | 008010500 33 | 460000012 34 | 070502080 35 | 000603000 36 | 040109030 37 | 250000098 38 | 001020600 39 | 080060020 40 | ======== 41 | 020810740 42 | 700003100 43 | 090002805 44 | 009040087 45 | 400208003 46 | 160030200 47 | 302700060 48 | 005600008 49 | 076051090 50 | ======== 51 | 100920000 52 | 524010000 53 | 000000070 54 | 050008102 55 | 000000000 56 | 402700090 57 | 060000000 58 | 000030945 59 | 000071006 60 | ======== 61 | 043080250 62 | 600000000 63 | 000001094 64 | 900004070 65 | 000608000 66 | 010200003 67 | 820500000 68 | 000000005 69 | 034090710 70 | ======== 71 | 480006902 72 | 002008001 73 | 900370060 74 | 840010200 75 | 003704100 76 | 001060049 77 | 020085007 78 | 700900600 79 | 609200018 80 | ======== 81 | 000900002 82 | 050123400 83 | 030000160 84 | 908000000 85 | 070000090 86 | 000000205 87 | 091000050 88 | 007439020 89 | 400007000 90 | ======== 91 | 001900003 92 | 900700160 93 | 030005007 94 | 050000009 95 | 004302600 96 | 200000070 97 | 600100030 98 | 042007006 99 | 500006800 100 | ======== 101 | 000125400 102 | 008400000 103 | 420800000 104 | 030000095 105 | 060902010 106 | 510000060 107 | 000003049 108 | 000007200 109 | 001298000 110 | ======== 111 | 062340750 112 | 100005600 113 | 570000040 114 | 000094800 115 | 400000006 116 | 005830000 117 | 030000091 118 | 006400007 119 | 059083260 120 | ======== 121 | 300000000 122 | 005009000 123 | 200504000 124 | 020000700 125 | 160000058 126 | 704310600 127 | 000890100 128 | 000067080 129 | 000005437 130 | ======== 131 | 630000000 132 | 000500008 133 | 005674000 134 | 000020000 135 | 003401020 136 | 000000345 137 | 000007004 138 | 080300902 139 | 947100080 140 | ======== 141 | 000020040 142 | 008035000 143 | 000070602 144 | 031046970 145 | 200000000 146 | 000501203 147 | 049000730 148 | 000000010 149 | 800004000 150 | ======== 151 | 361025900 152 | 080960010 153 | 400000057 154 | 008000471 155 | 000603000 156 | 259000800 157 | 740000005 158 | 020018060 159 | 005470329 160 | ======== 161 | 050807020 162 | 600010090 163 | 702540006 164 | 070020301 165 | 504000908 166 | 103080070 167 | 900076205 168 | 060090003 169 | 080103040 170 | ======== 171 | 080005000 172 | 000003457 173 | 000070809 174 | 060400903 175 | 007010500 176 | 408007020 177 | 901020000 178 | 842300000 179 | 000100080 180 | ======== 181 | 003502900 182 | 000040000 183 | 106000305 184 | 900251008 185 | 070408030 186 | 800763001 187 | 308000104 188 | 000020000 189 | 005104800 190 | ======== 191 | 000000000 192 | 009805100 193 | 051907420 194 | 290401065 195 | 000000000 196 | 140508093 197 | 026709580 198 | 005103600 199 | 000000000 200 | ======== 201 | 020030090 202 | 000907000 203 | 900208005 204 | 004806500 205 | 607000208 206 | 003102900 207 | 800605007 208 | 000309000 209 | 030020050 210 | ======== 211 | 005000006 212 | 070009020 213 | 000500107 214 | 804150000 215 | 000803000 216 | 000092805 217 | 907006000 218 | 030400010 219 | 200000600 220 | ======== 221 | 040000050 222 | 001943600 223 | 009000300 224 | 600050002 225 | 103000506 226 | 800020007 227 | 005000200 228 | 002436700 229 | 030000040 230 | ======== 231 | 004000000 232 | 000030002 233 | 390700080 234 | 400009001 235 | 209801307 236 | 600200008 237 | 010008053 238 | 900040000 239 | 000000800 240 | ======== 241 | 360020089 242 | 000361000 243 | 000000000 244 | 803000602 245 | 400603007 246 | 607000108 247 | 000000000 248 | 000418000 249 | 970030014 250 | ======== 251 | 500400060 252 | 009000800 253 | 640020000 254 | 000001008 255 | 208000501 256 | 700500000 257 | 000090084 258 | 003000600 259 | 060003002 260 | ======== 261 | 007256400 262 | 400000005 263 | 010030060 264 | 000508000 265 | 008060200 266 | 000107000 267 | 030070090 268 | 200000004 269 | 006312700 270 | ======== 271 | 000000000 272 | 079050180 273 | 800000007 274 | 007306800 275 | 450708096 276 | 003502700 277 | 700000005 278 | 016030420 279 | 000000000 280 | ======== 281 | 030000080 282 | 009000500 283 | 007509200 284 | 700105008 285 | 020090030 286 | 900402001 287 | 004207100 288 | 002000800 289 | 070000090 290 | ======== 291 | 200170603 292 | 050000100 293 | 000006079 294 | 000040700 295 | 000801000 296 | 009050000 297 | 310400000 298 | 005000060 299 | 906037002 300 | ======== 301 | 000000080 302 | 800701040 303 | 040020030 304 | 374000900 305 | 000030000 306 | 005000321 307 | 010060050 308 | 050802006 309 | 080000000 310 | ======== 311 | 000000085 312 | 000210009 313 | 960080100 314 | 500800016 315 | 000000000 316 | 890006007 317 | 009070052 318 | 300054000 319 | 480000000 320 | ======== 321 | 608070502 322 | 050608070 323 | 002000300 324 | 500090006 325 | 040302050 326 | 800050003 327 | 005000200 328 | 010704090 329 | 409060701 330 | ======== 331 | 050010040 332 | 107000602 333 | 000905000 334 | 208030501 335 | 040070020 336 | 901080406 337 | 000401000 338 | 304000709 339 | 020060010 340 | ======== 341 | 053000790 342 | 009753400 343 | 100000002 344 | 090080010 345 | 000907000 346 | 080030070 347 | 500000003 348 | 007641200 349 | 061000940 350 | ======== 351 | 006080300 352 | 049070250 353 | 000405000 354 | 600317004 355 | 007000800 356 | 100826009 357 | 000702000 358 | 075040190 359 | 003090600 360 | ======== 361 | 005080700 362 | 700204005 363 | 320000084 364 | 060105040 365 | 008000500 366 | 070803010 367 | 450000091 368 | 600508007 369 | 003010600 370 | ======== 371 | 000900800 372 | 128006400 373 | 070800060 374 | 800430007 375 | 500000009 376 | 600079008 377 | 090004010 378 | 003600284 379 | 001007000 380 | ======== 381 | 000080000 382 | 270000054 383 | 095000810 384 | 009806400 385 | 020403060 386 | 006905100 387 | 017000620 388 | 460000038 389 | 000090000 390 | ======== 391 | 000602000 392 | 400050001 393 | 085010620 394 | 038206710 395 | 000000000 396 | 019407350 397 | 026040530 398 | 900020007 399 | 000809000 400 | ======== 401 | 000900002 402 | 050123400 403 | 030000160 404 | 908000000 405 | 070000090 406 | 000000205 407 | 091000050 408 | 007439020 409 | 400007000 410 | ======== 411 | 380000000 412 | 000400785 413 | 009020300 414 | 060090000 415 | 800302009 416 | 000040070 417 | 001070500 418 | 495006000 419 | 000000092 420 | ======== 421 | 000158000 422 | 002060800 423 | 030000040 424 | 027030510 425 | 000000000 426 | 046080790 427 | 050000080 428 | 004070100 429 | 000325000 430 | ======== 431 | 010500200 432 | 900001000 433 | 002008030 434 | 500030007 435 | 008000500 436 | 600080004 437 | 040100700 438 | 000700006 439 | 003004050 440 | ======== 441 | 080000040 442 | 000469000 443 | 400000007 444 | 005904600 445 | 070608030 446 | 008502100 447 | 900000005 448 | 000781000 449 | 060000010 450 | ======== 451 | 904200007 452 | 010000000 453 | 000706500 454 | 000800090 455 | 020904060 456 | 040002000 457 | 001607000 458 | 000000030 459 | 300005702 460 | ======== 461 | 000700800 462 | 006000031 463 | 040002000 464 | 024070000 465 | 010030080 466 | 000060290 467 | 000800070 468 | 860000500 469 | 002006000 470 | ======== 471 | 001007090 472 | 590080001 473 | 030000080 474 | 000005800 475 | 050060020 476 | 004100000 477 | 080000030 478 | 100020079 479 | 020700400 480 | ======== 481 | 000003017 482 | 015009008 483 | 060000000 484 | 100007000 485 | 009000200 486 | 000500004 487 | 000000020 488 | 500600340 489 | 340200000 490 | ======== 491 | 300200000 492 | 000107000 493 | 706030500 494 | 070009080 495 | 900020004 496 | 010800050 497 | 009040301 498 | 000702000 499 | 000008006 -------------------------------------------------------------------------------- /problems/sudoku/hardest.txt: -------------------------------------------------------------------------------- 1 | 85...24..72......9..4.........1.7..23.5...9...4...........8..7..17..........36.4. 2 | ..53.....8......2..7..1.5..4....53...1..7...6..32...8..6.5....9..4....3......97.. 3 | 12..4......5.69.1...9...5.........7.7...52.9..3......2.9.6...5.4..9..8.1..3...9.4 4 | ...57..3.1......2.7...234......8...4..7..4...49....6.5.42...3.....7..9....18..... 5 | 7..1523........92....3.....1....47.8.......6............9...5.6.4.9.7...8....6.1. 6 | 1....7.9..3..2...8..96..5....53..9...1..8...26....4...3......1..4......7..7...3.. 7 | 1...34.8....8..5....4.6..21.18......3..1.2..6......81.52..7.9....6..9....9.64...2 8 | ...92......68.3...19..7...623..4.1....1...7....8.3..297...8..91...5.72......64... 9 | .6.5.4.3.1...9...8.........9...5...6.4.6.2.7.7...4...5.........4...8...1.5.2.3.4. 10 | 7.....4...2..7..8...3..8.799..5..3...6..2..9...1.97..6...3..9...3..4..6...9..1.35 11 | ....7..2.8.......6.1.2.5...9.54....8.........3....85.1...3.2.8.4.......9.7..6.... 12 | -------------------------------------------------------------------------------- /problems/sudoku/sudoku_brute_force.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # From http://mehpic.blogspot.com/2011/10/solve-any-sudoku-with-10-lines-of.html 4 | # 5 | 6 | input_board = [ 7 | 7,0,0,4,0,9,0,0,6, 8 | 5,0,9,0,8,6,1,2,0, 9 | 1,4,0,0,0,0,0,0,0, 10 | 6,5,0,8,0,0,0,0,0, 11 | 0,2,4,9,0,1,5,6,0, 12 | 0,0,0,0,0,2,0,1,8, 13 | 0,0,0,0,0,0,0,8,7, 14 | 0,7,5,2,4,0,6,0,1, 15 | 2,0,0,3,0,7,0,0,5 16 | ] 17 | 18 | board_size = 9 19 | subsquare_width = 3 20 | subsquare_height = 3 21 | 22 | def prettyprint(board, board_size): 23 | print 24 | for i in range(board_size): 25 | print board[i*board_size:i*board_size+board_size] 26 | 27 | 28 | col_labels = [i%board_size for i in range(len(input_board))] 29 | row_labels = [i/board_size for i in range(len(input_board))] 30 | sqr_labels = [(board_size/subsquare_width)*(row_labels[i]/subsquare_height)+col_labels[i]/subsquare_width for i in range(len(input_board))] 31 | 32 | 33 | def solve(board): 34 | try: 35 | i = board.index(0) 36 | except: 37 | prettyprint(board, board_size) 38 | return 39 | # find out numbers already used in same row, column or square. 40 | bag = [board[j] for j in filter(lambda x: (col_labels[i]==col_labels[x]) or (row_labels[i]==row_labels[x]) or (sqr_labels[i]==sqr_labels[x]),range(len(board)))] 41 | # get numbers can be used to put in a position 42 | for j in filter(lambda x: x not in bag, range(1,board_size+1)): 43 | # get one number, put in this position, call itself again. 44 | board[i] = j; solve(board); board[i] = 0 45 | 46 | solve(input_board) 47 | -------------------------------------------------------------------------------- /problems/sudoku/sudoku_norvig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ## Solve Every Sudoku Puzzle 3 | 4 | ## See http://norvig.com/sudoku.html 5 | 6 | ## Throughout this program we have: 7 | ## r is a row, e.g. 'A' 8 | ## c is a column, e.g. '3' 9 | ## s is a square, e.g. 'A3' 10 | ## d is a digit, e.g. '9' 11 | ## u is a unit, e.g. ['A1','B1','C1','D1','E1','F1','G1','H1','I1'] 12 | ## grid is a grid,e.g. 81 non-blank chars, e.g. starting with '.18...7... 13 | ## values is a dict of possible values, e.g. {'A1':'12349', 'A2':'8', ...} 14 | 15 | def cross(A, B): 16 | "Cross product of elements in A and elements in B." 17 | return [a+b for a in A for b in B] 18 | 19 | # digits can use set to improve efficiency. More than one place need to change. 20 | #digits = {1, 2, 3, 4, 5, 6, 7, 8, 9} 21 | 22 | digits = '123456789' 23 | rows = 'ABCDEFGHI' 24 | cols = digits 25 | squares = cross(rows, cols) 26 | unitlist = ([cross(rows, c) for c in cols] + 27 | [cross(r, cols) for r in rows] + 28 | [cross(rs, cs) for rs in ('ABC','DEF','GHI') for cs in ('123','456','789')]) 29 | units = dict((s, [u for u in unitlist if s in u]) 30 | for s in squares) 31 | peers = dict((s, set(sum(units[s],[]))-set([s])) 32 | for s in squares) 33 | 34 | ################ Unit Tests ################ 35 | 36 | def test(): 37 | "A set of tests that must pass." 38 | assert len(squares) == 81 39 | assert len(unitlist) == 27 40 | assert all(len(units[s]) == 3 for s in squares) 41 | assert all(len(peers[s]) == 20 for s in squares) 42 | assert units['C2'] == [['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2'], 43 | ['C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'], 44 | ['A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3']] 45 | assert peers['C2'] == set(['A2', 'B2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 46 | 'C1', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 47 | 'A1', 'A3', 'B1', 'B3']) 48 | print 'All tests pass.' 49 | 50 | ################ Parse a Grid ################ 51 | 52 | def parse_grid(grid): 53 | """Convert grid to a dict of possible values, {square: digits}, or 54 | return False if a contradiction is detected.""" 55 | ## To start, every square can be any digit; then assign values from the grid. 56 | values = dict((s, digits) for s in squares) 57 | for square,data in grid_values(grid).items(): 58 | if data in digits and not assign(values, square, data): 59 | return False ## (Fail if we can't assign data to square.) 60 | return values 61 | 62 | def grid_values(grid): 63 | """Convert grid into a dict of {square: char} with '0' or '.' for empties. 64 | i.e. {'A1': '0', 'A3': '4'} 65 | """ 66 | chars = [c for c in grid if c in digits or c in '0.'] 67 | assert len(chars) == 81 68 | return dict(zip(squares, chars)) 69 | 70 | ################ Constraint Propagation ################ 71 | 72 | def assign(values, s, d): 73 | """Eliminate all the other values (except d) from values[s] and propagate. 74 | Return values, except return False if a contradiction is detected.""" 75 | other_values = values[s].replace(d, '') 76 | if all(eliminate(values, s, d2) for d2 in other_values): 77 | return values 78 | else: 79 | return False 80 | 81 | def eliminate(values, s, d): 82 | """Eliminate d from values[s]; propagate when values or places <= 2. 83 | Return values, except return False if a contradiction is detected.""" 84 | if d not in values[s]: 85 | return values ## Already eliminated 86 | values[s] = values[s].replace(d,'') 87 | ## (1) If a square s is reduced to one value d2, then eliminate d2 from the peers. 88 | if len(values[s]) == 0: 89 | return False ## Contradiction: removed last value 90 | elif len(values[s]) == 1: 91 | d2 = values[s] 92 | if not all(eliminate(values, s2, d2) for s2 in peers[s]): 93 | return False 94 | ## (2) If a unit u is reduced to only one place for a value d, then put it there. 95 | for u in units[s]: 96 | dplaces = [s for s in u if d in values[s]] 97 | if len(dplaces) == 0: 98 | return False ## Contradiction: no place for this value 99 | elif len(dplaces) == 1: 100 | # d can only be in one place in unit; assign it there 101 | if not assign(values, dplaces[0], d): 102 | return False 103 | return values 104 | 105 | ################ Display as 2-D grid ################ 106 | 107 | def display(values): 108 | "Display these values as a 2-D grid." 109 | width = 1+max(len(values[s]) for s in squares) 110 | line = '+'.join(['-'*(width*3)]*3) 111 | for r in rows: 112 | print ''.join(values[r+c].center(width)+('|' if c in '36' else '') 113 | for c in cols) 114 | if r in 'CF': print line 115 | print 116 | 117 | ################ Search ################ 118 | 119 | def solve(grid): return search(parse_grid(grid)) 120 | 121 | def search(values): 122 | "Using depth-first search and propagation, try all possible values." 123 | if values is False: 124 | return False ## Failed earlier 125 | if all(len(values[s]) == 1 for s in squares): 126 | return values ## Solved! 127 | ## Chose the unfilled square s with the fewest possibilities 128 | n,s = min((len(values[s]), s) for s in squares if len(values[s]) > 1) 129 | return some(search(assign(values.copy(), s, d)) 130 | for d in values[s]) 131 | 132 | ################ Utilities ################ 133 | 134 | def some(seq): 135 | "Return some element of seq that is true." 136 | for e in seq: 137 | if e: return e 138 | return False 139 | 140 | def from_file(filename, sep='\n'): 141 | "Parse a file into a list of strings, separated by sep." 142 | return file(filename).read().strip().split(sep) 143 | 144 | def shuffled(seq): 145 | "Return a randomly shuffled copy of the input sequence." 146 | seq = list(seq) 147 | random.shuffle(seq) 148 | return seq 149 | 150 | ################ System test ################ 151 | 152 | import time, random 153 | 154 | def solve_all(grids, name='', showif=0.0): 155 | """Attempt to solve a sequence of grids. Report results. 156 | When showif is a number of seconds, display puzzles that take longer. 157 | When showif is None, don't display any puzzles.""" 158 | def time_solve(grid): 159 | start = time.clock() 160 | values = solve(grid) 161 | t = time.clock()-start 162 | ## Display puzzles that take long enough 163 | if showif is not None and t > showif: 164 | display(grid_values(grid)) 165 | if values: display(values) 166 | print '(%.2f seconds)\n' % t 167 | return (t, solved(values)) 168 | times, results = zip(*[time_solve(grid) for grid in grids]) 169 | N = len(grids) 170 | if N > 1: 171 | print "Solved %d of %d %s puzzles (avg %.2f secs (%d Hz), max %.2f secs)." % ( 172 | sum(results), N, name, sum(times)/N, N/sum(times), max(times)) 173 | else: 174 | print "Solved %d of %d %s puzzles (avg %.2f secs, max %.2f secs)." % ( 175 | sum(results), N, name, sum(times)/N, max(times)) 176 | 177 | def solved(values): 178 | "A puzzle is solved if each unit is a permutation of the digits 1 to 9." 179 | def unitsolved(unit): return set(values[s] for s in unit) == set(digits) 180 | return values is not False and all(unitsolved(unit) for unit in unitlist) 181 | 182 | def random_puzzle(N=17): 183 | """Make a random puzzle with N or more assignments. Restart on contradictions. 184 | Note the resulting puzzle is not guaranteed to be solvable, but empirically 185 | about 99.8% of them are solvable. Some have multiple solutions.""" 186 | values = dict((s, digits) for s in squares) 187 | for s in shuffled(squares): 188 | if not assign(values, s, random.choice(values[s])): 189 | break 190 | ds = [values[s] for s in squares if len(values[s]) == 1] 191 | if len(ds) >= N and len(set(ds)) >= 8: 192 | return ''.join(values[s] if len(values[s])==1 else '.' for s in squares) 193 | return random_puzzle(N) ## Give up and make a new puzzle 194 | 195 | grid1 = '003020600900305001001806400008102900700000008006708200002609500800203009005010300' 196 | grid2 = '4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......' 197 | hard1 = '.....6....59.....82....8....45........3........6..3.54...325..6..................' 198 | snyder = '.5..2..3.2....17.84.76..........5...52.....47...7..........35.43.65....1.9..7..6.' 199 | 200 | if __name__ == '__main__': 201 | test() 202 | solve_all([snyder], "snyder", None) 203 | solve_all(from_file("easy50.txt", '========'), "easy", None) 204 | solve_all(from_file("top95.txt"), "hard", None) 205 | solve_all(from_file("hardest.txt"), "hardest", None) 206 | solve_all([random_puzzle() for _ in range(99)], "random", 100.0) 207 | 208 | ## References used: 209 | ## http://www.scanraid.com/BasicStrategies.htm 210 | ## http://www.sudokudragon.com/sudokustrategy.htm 211 | ## http://www.krazydad.com/blog/2005/09/29/an-index-of-sudoku-strategies/ 212 | ## http://www2.warwick.ac.uk/fac/sci/moac/currentstudents/peter_cock/python/sudoku/ 213 | -------------------------------------------------------------------------------- /problems/sudoku/top95.txt: -------------------------------------------------------------------------------- 1 | 4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4...... 2 | 52...6.........7.13...........4..8..6......5...........418.........3..2...87..... 3 | 6.....8.3.4.7.................5.4.7.3..2.....1.6.......2.....5.....8.6......1.... 4 | 48.3............71.2.......7.5....6....2..8.............1.76...3.....4......5.... 5 | ....14....3....2...7..........9...3.6.1.............8.2.....1.4....5.6.....7.8... 6 | ......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3. 7 | 6.2.5.........3.4..........43...8....1....2........7..5..27...........81...6..... 8 | .524.........7.1..............8.2...3.....6...9.5.....1.6.3...........897........ 9 | 6.2.5.........4.3..........43...8....1....2........7..5..27...........81...6..... 10 | .923.........8.1...........1.7.4...........658.........6.5.2...4.....7.....9..... 11 | 6..3.2....5.....1..........7.26............543.........8.15........4.2........7.. 12 | .6.5.1.9.1...9..539....7....4.8...7.......5.8.817.5.3.....5.2............76..8... 13 | ..5...987.4..5...1..7......2...48....9.1.....6..2.....3..6..2.......9.7.......5.. 14 | 3.6.7...........518.........1.4.5...7.....6.....2......2.....4.....8.3.....5..... 15 | 1.....3.8.7.4..............2.3.1...........958.........5.6...7.....8.2...4....... 16 | 6..3.2....4.....1..........7.26............543.........8.15........4.2........7.. 17 | ....3..9....2....1.5.9..............1.2.8.4.6.8.5...2..75......4.1..6..3.....4.6. 18 | 45.....3....8.1....9...........5..9.2..7.....8.........1..4..........7.2...6..8.. 19 | .237....68...6.59.9.....7......4.97.3.7.96..2.........5..47.........2....8....... 20 | ..84...3....3.....9....157479...8........7..514.....2...9.6...2.5....4......9..56 21 | .98.1....2......6.............3.2.5..84.........6.........4.8.93..5...........1.. 22 | ..247..58..............1.4.....2...9528.9.4....9...1.........3.3....75..685..2... 23 | 4.....8.5.3..........7......2.....6.....5.4......1.......6.3.7.5..2.....1.9...... 24 | .2.3......63.....58.......15....9.3....7........1....8.879..26......6.7...6..7..4 25 | 1.....7.9.4...72..8.........7..1..6.3.......5.6..4..2.........8..53...7.7.2....46 26 | 4.....3.....8.2......7........1...8734.......6........5...6........1.4...82...... 27 | .......71.2.8........4.3...7...6..5....2..3..9........6...7.....8....4......5.... 28 | 6..3.2....4.....8..........7.26............543.........8.15........8.2........7.. 29 | .47.8...1............6..7..6....357......5....1..6....28..4.....9.1...4.....2.69. 30 | ......8.17..2........5.6......7...5..1....3...8.......5......2..4..8....6...3.... 31 | 38.6.......9.......2..3.51......5....3..1..6....4......17.5..8.......9.......7.32 32 | ...5...........5.697.....2...48.2...25.1...3..8..3.........4.7..13.5..9..2...31.. 33 | .2.......3.5.62..9.68...3...5..........64.8.2..47..9....3.....1.....6...17.43.... 34 | .8..4....3......1........2...5...4.69..1..8..2...........3.9....6....5.....2..... 35 | ..8.9.1...6.5...2......6....3.1.7.5.........9..4...3...5....2...7...3.8.2..7....4 36 | 4.....5.8.3..........7......2.....6.....5.8......1.......6.3.7.5..2.....1.8...... 37 | 1.....3.8.6.4..............2.3.1...........958.........5.6...7.....8.2...4....... 38 | 1....6.8..64..........4...7....9.6...7.4..5..5...7.1...5....32.3....8...4........ 39 | 249.6...3.3....2..8.......5.....6......2......1..4.82..9.5..7....4.....1.7...3... 40 | ...8....9.873...4.6..7.......85..97...........43..75.......3....3...145.4....2..1 41 | ...5.1....9....8...6.......4.1..........7..9........3.8.....1.5...2..4.....36.... 42 | ......8.16..2........7.5......6...2..1....3...8.......2......7..3..8....5...4.... 43 | .476...5.8.3.....2.....9......8.5..6...1.....6.24......78...51...6....4..9...4..7 44 | .....7.95.....1...86..2.....2..73..85......6...3..49..3.5...41724................ 45 | .4.5.....8...9..3..76.2.....146..........9..7.....36....1..4.5..6......3..71..2.. 46 | .834.........7..5...........4.1.8..........27...3.....2.6.5....5.....8........1.. 47 | ..9.....3.....9...7.....5.6..65..4.....3......28......3..75.6..6...........12.3.8 48 | .26.39......6....19.....7.......4..9.5....2....85.....3..2..9..4....762.........4 49 | 2.3.8....8..7...........1...6.5.7...4......3....1............82.5....6...1....... 50 | 6..3.2....1.....5..........7.26............843.........8.15........8.2........7.. 51 | 1.....9...64..1.7..7..4.......3.....3.89..5....7....2.....6.7.9.....4.1....129.3. 52 | .........9......84.623...5....6...453...1...6...9...7....1.....4.5..2....3.8....9 53 | .2....5938..5..46.94..6...8..2.3.....6..8.73.7..2.........4.38..7....6..........5 54 | 9.4..5...25.6..1..31......8.7...9...4..26......147....7.......2...3..8.6.4.....9. 55 | ...52.....9...3..4......7...1.....4..8..453..6...1...87.2........8....32.4..8..1. 56 | 53..2.9...24.3..5...9..........1.827...7.........981.............64....91.2.5.43. 57 | 1....786...7..8.1.8..2....9........24...1......9..5...6.8..........5.9.......93.4 58 | ....5...11......7..6.....8......4.....9.1.3.....596.2..8..62..7..7......3.5.7.2.. 59 | .47.2....8....1....3....9.2.....5...6..81..5.....4.....7....3.4...9...1.4..27.8.. 60 | ......94.....9...53....5.7..8.4..1..463...........7.8.8..7.....7......28.5.26.... 61 | .2......6....41.....78....1......7....37.....6..412....1..74..5..8.5..7......39.. 62 | 1.....3.8.6.4..............2.3.1...........758.........7.5...6.....8.2...4....... 63 | 2....1.9..1..3.7..9..8...2.......85..6.4.........7...3.2.3...6....5.....1.9...2.5 64 | ..7..8.....6.2.3...3......9.1..5..6.....1.....7.9....2........4.83..4...26....51. 65 | ...36....85.......9.4..8........68.........17..9..45...1.5...6.4....9..2.....3... 66 | 34.6.......7.......2..8.57......5....7..1..2....4......36.2..1.......9.......7.82 67 | ......4.18..2........6.7......8...6..4....3...1.......6......2..5..1....7...3.... 68 | .4..5..67...1...4....2.....1..8..3........2...6...........4..5.3.....8..2........ 69 | .......4...2..4..1.7..5..9...3..7....4..6....6..1..8...2....1..85.9...6.....8...3 70 | 8..7....4.5....6............3.97...8....43..5....2.9....6......2...6...7.71..83.2 71 | .8...4.5....7..3............1..85...6.....2......4....3.26............417........ 72 | ....7..8...6...5...2...3.61.1...7..2..8..534.2..9.......2......58...6.3.4...1.... 73 | ......8.16..2........7.5......6...2..1....3...8.......2......7..4..8....5...3.... 74 | .2..........6....3.74.8.........3..2.8..4..1.6..5.........1.78.5....9..........4. 75 | .52..68.......7.2.......6....48..9..2..41......1.....8..61..38.....9...63..6..1.9 76 | ....1.78.5....9..........4..2..........6....3.74.8.........3..2.8..4..1.6..5..... 77 | 1.......3.6.3..7...7...5..121.7...9...7........8.1..2....8.64....9.2..6....4..... 78 | 4...7.1....19.46.5.....1......7....2..2.3....847..6....14...8.6.2....3..6...9.... 79 | ......8.17..2........5.6......7...5..1....3...8.......5......2..3..8....6...4.... 80 | 963......1....8......2.5....4.8......1....7......3..257......3...9.2.4.7......9.. 81 | 15.3......7..4.2....4.72.....8.........9..1.8.1..8.79......38...........6....7423 82 | ..........5724...98....947...9..3...5..9..12...3.1.9...6....25....56.....7......6 83 | ....75....1..2.....4...3...5.....3.2...8...1.......6.....1..48.2........7........ 84 | 6.....7.3.4.8.................5.4.8.7..2.....1.3.......2.....5.....7.9......1.... 85 | ....6...4..6.3....1..4..5.77.....8.5...8.....6.8....9...2.9....4....32....97..1.. 86 | .32.....58..3.....9.428...1...4...39...6...5.....1.....2...67.8.....4....95....6. 87 | ...5.3.......6.7..5.8....1636..2.......4.1.......3...567....2.8..4.7.......2..5.. 88 | .5.3.7.4.1.........3.......5.8.3.61....8..5.9.6..1........4...6...6927....2...9.. 89 | ..5..8..18......9.......78....4.....64....9......53..2.6.........138..5....9.714. 90 | ..........72.6.1....51...82.8...13..4.........37.9..1.....238..5.4..9.........79. 91 | ...658.....4......12............96.7...3..5....2.8...3..19..8..3.6.....4....473.. 92 | .2.3.......6..8.9.83.5........2...8.7.9..5........6..4.......1...1...4.22..7..8.9 93 | .5..9....1.....6.....3.8.....8.4...9514.......3....2..........4.8...6..77..15..6. 94 | .....2.......7...17..3...9.8..7......2.89.6...13..6....9..5.824.....891.......... 95 | 3...8.......7....51..............36...2..4....7...........6.13..452...........8.. 96 | -------------------------------------------------------------------------------- /sorting/2011-10-19.00:29:17.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigbighd604/Python/0e65672ad7bcd9e60d1f43837156ae94edb41027/sorting/2011-10-19.00:29:17.pdf -------------------------------------------------------------------------------- /sorting/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigbighd604/Python/0e65672ad7bcd9e60d1f43837156ae94edb41027/sorting/__init__.py -------------------------------------------------------------------------------- /sorting/algorithms.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Oct 17, 2011 3 | 4 | @author: bighead 5 | ''' 6 | 7 | def BubbleSort(data): 8 | length = len(data) 9 | if length <= 1: 10 | return data 11 | for i in range(length - 1): 12 | for j in range(length - i - 1): 13 | if data[j] > data[j + 1]: 14 | data[j], data[j + 1] = data[j + 1], data[j] 15 | return data 16 | 17 | 18 | def SelectionSort(data): 19 | length = len(data) 20 | if length <= 1: 21 | return data 22 | 23 | for i in range(length - 1): 24 | min_value = data[i] 25 | min_index = i 26 | for j in range(i + 1, length): 27 | if min_value > data[j]: 28 | min_value = data[j] 29 | min_index = j 30 | if min_index != i: 31 | data[min_index] = data[i] 32 | data[i] = min_value 33 | return data 34 | 35 | 36 | def InsertionSort(data): 37 | length = len(data) 38 | if length <= 1: 39 | return data 40 | 41 | for i in range(1, length): 42 | item = data[i] 43 | for j in range(i): 44 | if item < data[i - j - 1]: 45 | data[i - j] = data[i - j - 1] 46 | data[i - j - 1] = item 47 | else: 48 | break 49 | return data 50 | 51 | 52 | def QuickSort(data): 53 | length = len(data) 54 | if length <= 1: 55 | return data 56 | pivot_index = length / 2 57 | pivot = data[pivot_index] 58 | left = [] 59 | right = [] 60 | for item in data[:pivot_index] + data[pivot_index + 1:]: 61 | if item <= pivot: 62 | left.append(item) 63 | else: 64 | right.append(item) 65 | 66 | return QuickSort(left) + [pivot] + QuickSort(right) 67 | 68 | 69 | def MergeList(a, b): 70 | while a or b: 71 | if not a: 72 | yield b.pop(0) 73 | elif not b: 74 | yield a.pop(0) 75 | elif a[0] < b[0]: 76 | yield a.pop(0) 77 | else: 78 | yield b.pop(0) 79 | 80 | 81 | def MergeSort(data): 82 | length = len(data) 83 | if length <= 1: 84 | return data 85 | 86 | return list(MergeList(MergeSort(data[:length / 2]), MergeSort(data[length / 2:]))) 87 | 88 | 89 | def CountingSort(data): 90 | assert all(0 <= x <= 50000 for x in data) 91 | counter = [0] * 50001 92 | for item in data: 93 | counter[item] += 1 94 | for x, count in enumerate(counter): 95 | for i in range(count): 96 | yield x 97 | 98 | 99 | def CountingSortWrapper(data): 100 | return list(CountingSort(data)) 101 | 102 | 103 | def Digit(x, k): 104 | return (x / (10 ** k)) % 10 105 | 106 | 107 | def SortByDigit(data, k): 108 | buckets = [[] for i in range(10)] 109 | for x in data: 110 | buckets[Digit(x, k)].append(x) 111 | for b in buckets: 112 | for x in b: 113 | yield x 114 | 115 | 116 | def RadixSort(data, digit = 5): 117 | for k in range(digit): 118 | data = SortByDigit(data, k) 119 | return list(data) 120 | 121 | class Heap(list): 122 | def FindMin(self): 123 | return self[0] 124 | 125 | def Parent(self, i): 126 | return (i - 1) / 2 127 | 128 | def Children(self, i): 129 | return i * 2 + 1, i * 2 + 2 130 | 131 | def Insert(self, e): 132 | self.append(e) 133 | i = len(self) - 1 134 | while i > 0: 135 | p = self.Parent(i) 136 | if self[p] > self[i]: 137 | self[p], self[i] = self[i], self[p] 138 | i = p 139 | else: 140 | return 141 | 142 | def DeleteMin(self): 143 | minimal = self[0] 144 | n = len(self) - 1 145 | self[0] = self[n] 146 | del self[n] 147 | 148 | i = 0 149 | while True: 150 | left, right = self.Children(i) 151 | if right < n and self[right] < self[left]: 152 | child = right 153 | elif left < n: 154 | child = left 155 | else: 156 | return minimal 157 | if self[child] < self[i]: 158 | self[i], self[child] = self[child], self[i] 159 | i = child 160 | else: 161 | return minimal 162 | 163 | 164 | def HeapSort(data): 165 | heap = Heap() 166 | for element in data: 167 | heap.Insert(element) 168 | while heap: 169 | yield heap.DeleteMin() 170 | 171 | def HeapSortWrapper(data): 172 | return list(HeapSort(data)) 173 | -------------------------------------------------------------------------------- /sorting/common.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Oct 17, 2011 3 | 4 | @author: bighead 5 | ''' 6 | 7 | import random 8 | import time 9 | 10 | import algorithms 11 | 12 | 13 | def GenerateList(size = 100): 14 | data = [ random.randint(0, 50000) for i in range(size) ] 15 | return data 16 | 17 | 18 | def TimeWorker(algorithm, data_size): 19 | data = GenerateList(data_size) 20 | start_time = time.clock() # Returns floating point number of seconds 21 | result = getattr(algorithms, algorithm)(data) 22 | stop_time = time.clock() 23 | return (stop_time - start_time, result) 24 | 25 | 26 | def TimeAlgorithm(algorithms = None, min_size = 0, max_size = 100000, 27 | step = 500, enable_threshold = False, threshold = 20, 28 | print_result = False): 29 | all_time_list = [] 30 | all_number_list = [] 31 | if algorithms: 32 | algorithms_status = {} 33 | for algorithm in algorithms: 34 | algorithms_status[algorithm] = [True, None] 35 | 36 | for size in range(min_size, max_size, step): 37 | time_list = [] 38 | number_list = [] 39 | for algorithm in algorithms: 40 | if enable_threshold and algorithms_status[algorithm][0]: 41 | process_time, result = TimeWorker(algorithm, size) 42 | if process_time >= threshold: 43 | algorithms_status[algorithm] = (False, process_time) 44 | print('Algorithm: %s stops running due to exceed threshold time: %s' % (algorithm, threshold)) 45 | elif enable_threshold: 46 | process_time = algorithms_status[algorithm][1] 47 | else: 48 | process_time, result = TimeWorker(algorithm, size) 49 | print('[Algorithm: %s, Data Size: %s, Process Time: %s' % (algorithm, size, process_time)) 50 | time_list.append(process_time) 51 | number_list.append(size) 52 | if print_result: 53 | print(result) 54 | all_time_list.append(time_list) 55 | all_number_list.append(number_list) 56 | return (all_number_list, all_time_list) 57 | -------------------------------------------------------------------------------- /sorting/heapq.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | def ReBalance(alist, i): 5 | length = len(alist) 6 | index = i 7 | if (2 * i) < length and alist[i] < alist[2 * i]: 8 | index = 2 * i 9 | if (2* i + 1) < length and alist[index] < alist[2 * i + 1]: 10 | index = index + 1 11 | if index != i: 12 | alist[i], alist[index] = alist[index], alist[i] 13 | ReBalance(alist, index) 14 | 15 | 16 | def GetHeap(alist): 17 | length = len(alist) 18 | start = length / 2 - 1 19 | 20 | for i in range(start, 0, -1): 21 | ReBalance(alist, i) 22 | return alist 23 | 24 | 25 | if __name__ == '__main__': 26 | alist = [5, 13, 2, 25, 7, 17, 20, 8, 4] 27 | print GetHeap(alist) 28 | -------------------------------------------------------------------------------- /sorting/main.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Oct 17, 2011 3 | 4 | @author: bighead 5 | ''' 6 | 7 | import csv 8 | import time 9 | import matplotlib.pyplot as plt 10 | 11 | import common 12 | 13 | 14 | def main(): 15 | algorithm_list = ('BubbleSort', 'SelectionSort', 'InsertionSort', 16 | 'QuickSort', 'MergeSort', 'CountingSortWrapper', 17 | 'RadixSort', 'HeapSortWrapper') 18 | #algorithm_list = ('QuickSort', 'MergeSort', 'CountingSortWrapper', 'HeapSortWrapper') 19 | number_list, time_list = common.TimeAlgorithm(algorithm_list, 20 | max_size = 500000, 21 | step = 1000, 22 | enable_threshold = True) 23 | file_name = '%s' % time.strftime('%Y-%m-%d.%H:%M:%S') 24 | plt.figlegend(plt.plot(number_list, time_list), algorithm_list, 'upper left') 25 | plt.savefig('%s.pdf' % file_name) 26 | csv_writer = csv.writer(open('%s.csv' % file_name, 'wb'), delimiter = ',') 27 | csv_writer.writenow(["Title"] + number_list) 28 | for i in range(len(algorithm_list)): 29 | time_data = [item[i] for item in time_list] 30 | csv_writer.writenow([algorithm_list[i]] + time_data) 31 | 32 | 33 | if __name__ == "__main__": 34 | main() 35 | -------------------------------------------------------------------------------- /spoj.pl/ADDRE.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | num_map = { 4 | '0':0, '1':1, '2':2, '3':3, '4':4 5 | '5':5, '6':6, '7':7, '8':8, '9':9 6 | } 7 | 8 | 9 | if __name__ == '__main__': 10 | lines = int(raw_input()) 11 | for i in xrange(lines): 12 | n1, n2 = raw_input().split() 13 | n1 = n1[::-1] 14 | n2 = n2[::-1] 15 | n3 = int(n1) + int(n2) 16 | print str(n3)[::-1].strip('0') 17 | -------------------------------------------------------------------------------- /spoj.pl/BANDW.input: -------------------------------------------------------------------------------- 1 | BBNBBNBBBB NNNNNBBNNB 2 | BNBNB NBNBN 3 | BNBN NBNB 4 | B B 5 | * * 6 | -------------------------------------------------------------------------------- /spoj.pl/BANDW.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | def calculate(source, target): 5 | counter = 0 6 | flag = False 7 | for i, c in enumerate(source): 8 | if c != target[i]: 9 | if not flag: 10 | flag = True 11 | counter += 1 12 | elif flag: 13 | flag = False 14 | 15 | return counter 16 | 17 | 18 | if __name__ == '__main__': 19 | while True: 20 | s, t = (raw_input()).split() 21 | if s != '*': 22 | print calculate(s, t) 23 | else: 24 | break 25 | -------------------------------------------------------------------------------- /spoj.pl/FCTRL.input: -------------------------------------------------------------------------------- 1 | 6 2 | 3 3 | 60 4 | 100 5 | 1024 6 | 23456 7 | 8735373 8 | -------------------------------------------------------------------------------- /spoj.pl/FCTRL.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # https://www.spoj.pl/problems/FCTRL 4 | # 5 | 6 | 7 | def GetZeros(number): 8 | zeros = 0 9 | value = 5 10 | counter = 0 11 | 12 | while value <= number: 13 | value *= 5 14 | counter += 1 15 | 16 | for i in xrange(1, counter+1): 17 | zeros += number / (5 ** i) 18 | 19 | return zeros 20 | 21 | 22 | if __name__ == '__main__': 23 | num = int(raw_input()) 24 | numbers = [] 25 | results = [] 26 | 27 | for i in xrange(num): 28 | numbers.append(int(raw_input())) 29 | 30 | for i in numbers: 31 | results.append(GetZeros(i)) 32 | 33 | print '\n'.join([str(result) for result in results]) 34 | -------------------------------------------------------------------------------- /spoj.pl/PRIME1.input: -------------------------------------------------------------------------------- 1 | 4 2 | 1 10 3 | 3 5 4 | 999900000 1000000000 5 | 899900000 900000000 6 | -------------------------------------------------------------------------------- /spoj.pl/PRIME1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import time 4 | 5 | prime_list = [] 6 | 7 | 8 | def is_prime(num): 9 | for i in xrange(len(prime_list)): 10 | p = prime_list[i] 11 | if (p * p > num): return True 12 | if (num % p == 0): return False 13 | return True 14 | 15 | 16 | def generate_list(): 17 | prime_list.append(2) 18 | for i in xrange(3, 32000, 2): 19 | if is_prime(i): 20 | prime_list.append(i) 21 | 22 | 23 | def calculate(start, end): 24 | result = [] 25 | if (start <= 2): 26 | result.append(2) 27 | start = 3 28 | if (start % 2 == 0): start += 1 29 | 30 | # TODO(andrewlv): only need to check up to sqrt(num) to test prime. 31 | for i in xrange(start, end + 1, 2): 32 | if is_prime(i): 33 | result.append(i) 34 | 35 | return result 36 | 37 | 38 | if __name__ == '__main__': 39 | pairs = int(raw_input()) 40 | pair_list = [] 41 | for i in xrange(pairs): 42 | start, end = raw_input().split() 43 | pair_list.append((int(start), int(end))) 44 | 45 | generate_list() 46 | for start, end in pair_list: 47 | result = calculate(start, end) 48 | print '\n'.join(map(str, result)) 49 | print '' 50 | -------------------------------------------------------------------------------- /spoj.pl/a.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) { 4 | int i; 5 | 6 | for (i = 0; i < 5; i++) { 7 | int n; 8 | scanf("%d", &n); 9 | printf("n = %d\n", n); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /strings/Boyer-Moore.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # 4 | 5 | 6 | def IsPrefix(string, position): 7 | """Test if the suffix of string starting from position is a prefix of string. 8 | Args: 9 | string: A literal string. 10 | position: A integer indicates the position. 11 | 12 | Returns: 13 | True if is a prefix, or False. 14 | """ 15 | length = len(string) 16 | suffix_length = length - position 17 | counter = 0 18 | while (counter < suffix_length and 19 | string[counter] == string[position + counter]): 20 | counter += 1 21 | return not (counter < suffix_length) 22 | 23 | 24 | def SuffixLength(str, pos): 25 | """length of the longest suffix of string ending on position. 26 | Args: 27 | string: A literal string. 28 | position: A integer indicates the position. 29 | 30 | Returns: 31 | A integer. 32 | """ 33 | length = len(str) 34 | counter = 0 35 | # increment suffix length to the first mismatch or beginning of str. 36 | while (str[pos - counter] == str[length - 1 - counter]) and (counter < pos): 37 | counter += 1 38 | return counter 39 | 40 | 41 | if __name__ == "__main__": 42 | str1 = "abcfefabcf" 43 | print IsPrefix(str1, 6) 44 | str2 = "dddbcabc" 45 | print SuffixLength(str2, 4) 46 | -------------------------------------------------------------------------------- /strings/Knuth-Morris-Pratt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # string search algorithm KMP 5 | # It use failure function to determine steps to fallback 6 | # http://en.wikipedia.org/wiki/Knuth–Morris–Pratt_algorithm 7 | # 8 | 9 | 10 | def BuildFailureFunction(needle): 11 | length = len(needle) 12 | failure_table = [0 for i in xrange(length)] 13 | failure_table[0] = -1 14 | position = 2 15 | index = 0 16 | while position < length: 17 | # first case: the substring continues 18 | if needle[position - 1] == needle[index]: 19 | index += 1 20 | failure_table[position] = index 21 | position += 1 22 | # second case: it doesn't but we can fall back 23 | elif index > 0: 24 | index = failure_table[index] 25 | # third case: we have run out of candiates. index = 0 26 | else: 27 | failure_table[position] = 0 28 | position += 1 29 | return failure_table 30 | 31 | 32 | def KMPSearch(haystack, needle): 33 | haystack_length = len(haystack) 34 | needle_length = len(needle) 35 | failure_table = BuildFailureFunction(needle) 36 | 37 | m = 0 # the beginning of the current match in haystack 38 | i = 0 # the position of the current character in needle 39 | 40 | while m + i < haystack_length: 41 | if needle[i] == haystack[m + i]: 42 | if i == needle_length - 1: 43 | return m 44 | i += 1 45 | else: 46 | m = m + i - failure_table[i] 47 | if failure_table[i] > -1: 48 | i = failure_table[i] 49 | else: 50 | i = 0 51 | print 'Jump to %s, set i to %s' % (m, i) 52 | return -1 53 | 54 | 55 | if __name__ == "__main__": 56 | print BuildFailureFunction("ABABABCABABD") 57 | print BuildFailureFunction("AAAAAAAD") 58 | print BuildFailureFunction("ABCDEABCDEFABCDED") 59 | needle = "ABCDABD" 60 | haystack = "ABC ABCDAB ABCDABCDABDE" 61 | print 'needle: %s' % needle 62 | print 'failure function: %s' % BuildFailureFunction(needle) 63 | print 'haystack: %s' % haystack 64 | print 'Match position: %s' % KMPSearch(haystack, needle) 65 | needle = "PARTICIPATE IN PARACHUTE" 66 | print BuildFailureFunction(needle) 67 | -------------------------------------------------------------------------------- /strings/near-words2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from string import ascii_lowercase as chars 4 | 5 | def DiffOneLetter(wd, words): # 6 | wasl = list(wd) # 7 | for i, c in enumerate(wasl): # 8 | for oc in chars: # 9 | if c == oc: continue # 10 | wasl[i] = oc # 11 | ow = ''.join(wasl) # 12 | if ow in words: # 13 | yield ow # 14 | wasl[i] = c # 15 | 16 | 17 | if __name__ == '__main__': 18 | wds = set(line.strip().lower() for line in open("/usr/share/dict/words")) 19 | print list(DiffOneLetter('cat', wds)) 20 | print list(DiffOneLetter('stack', wds)) 21 | -------------------------------------------------------------------------------- /strings/word-ladder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Use A Star to find word ladder. 4 | # heuristic function is the difference letters of 2 words. 5 | # 6 | 7 | 8 | from heapq import heappush, heappop 9 | from string import ascii_lowercase as chars 10 | 11 | 12 | inf = float('inf') 13 | global counter # How many words examined to find a path. 14 | 15 | def a_star(graph, start, target, heuristic): 16 | global counter 17 | counter = 0 18 | parents, queue = {}, [(heuristic(start), None, start)] 19 | while queue: 20 | counter += 1 21 | distance, parent, candidate = heappop(queue) 22 | if candidate in parents: continue 23 | parents[candidate] = parent 24 | if candidate == target: 25 | return distance - heuristic(target), parents 26 | for neighbor in graph[candidate]: 27 | weight = graph[candidate][neighbor] - heuristic(candidate) + heuristic(neighbor) 28 | heappush(queue, (distance + weight, candidate, neighbor)) 29 | return inf, None 30 | 31 | 32 | class WordNeighbors(object): 33 | 34 | def __init__(self, words): 35 | self.words = words 36 | self.M = dict() # Neighbor words 37 | 38 | def variants(self, wd, words): # Yield all word variants 39 | wasl = list(wd) # Convert word to a list 40 | for i, c in enumerate(wasl): # Each position and character 41 | for oc in chars: # Every possible character 42 | if c == oc: continue # Skip the same character 43 | wasl[i] = oc # Replace the character 44 | ow = ''.join(wasl) # Make a string of the word 45 | if ow in words: # Is it a valid word? 46 | yield ow # Yield it 47 | wasl[i] = c # Reset the character 48 | 49 | 50 | def __getitem__(self, wd): 51 | if wd not in self.M: 52 | # Cache the direct neighbors 53 | self.M[wd] = dict.fromkeys(self.variants(wd, self.words), 1) 54 | return self.M[wd] 55 | 56 | 57 | def heuristic(self, u, v): 58 | return sum(a!=b for a, b in zip(u, v)) 59 | 60 | 61 | def ladder(self, s, t, h=None): 62 | if h is None: 63 | def h(v): 64 | return self.heuristic(v, t) 65 | 66 | _, P = a_star(self, s, t, h) 67 | if P is None: 68 | return [s, None, t] 69 | 70 | u, p = t, [] 71 | while u is not None: # Get path to target 72 | p.append(u) 73 | u = P[u] 74 | 75 | p.reverse() # The path is backward 76 | return p 77 | 78 | 79 | if __name__ == '__main__': 80 | wds = set(line.strip().lower() for line in open("/usr/share/dict/words")) 81 | G = WordNeighbors(wds) 82 | print G.ladder('lead', 'gold') 83 | print G.ladder('teamwork', 'vacation') 84 | print G.ladder('axe', 'pie') 85 | print G.ladder('axe', 'pie', h = lambda v: 0) 86 | print counter, G.ladder('camera', 'harder') 87 | print counter, G.ladder('camera', 'harder', h = lambda v: 0) 88 | -------------------------------------------------------------------------------- /strings/word-ladder_v2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Use A Star to find word ladder. 4 | # heuristic function is the difference letters of 2 words. 5 | # 6 | 7 | 8 | from heapq import heappush, heappop 9 | from string import ascii_lowercase as chars 10 | 11 | 12 | inf = float('inf') 13 | global counter # How many words examined to find a path. 14 | 15 | def a_star(graph, start, target, heuristic): 16 | global counter 17 | counter = 0 18 | parents, queue = {}, [(heuristic(start), None, start)] 19 | while queue: 20 | counter += 1 21 | distance, parent, candidate = heappop(queue) 22 | if candidate in parents: continue 23 | parents[candidate] = parent 24 | if candidate == target: 25 | return distance - heuristic(target), parents 26 | for neighbor in graph[candidate]: 27 | weight = graph[candidate][neighbor] - heuristic(candidate) + heuristic(neighbor) 28 | heappush(queue, (distance + weight, candidate, neighbor)) 29 | return inf, None 30 | 31 | 32 | class WordNeighbors(object): 33 | 34 | def __init__(self, words): 35 | self.words = words 36 | self.M = dict() # Neighbor words 37 | 38 | def variants(self, wd, words): # Yield all word variants 39 | wasl = list(wd) # Convert word to a list 40 | for i, c in enumerate(wasl): # Each position and character 41 | for oc in chars: # Every possible character 42 | if c == oc: continue # Skip the same character 43 | wasl[i] = oc # Replace the character 44 | ow = ''.join(wasl) # Make a string of the word 45 | if ow in words: # Is it a valid word? 46 | yield ow # Yield it 47 | wasl[i] = c # Reset the character 48 | 49 | 50 | def __getitem__(self, wd): 51 | if wd not in self.M: 52 | # Cache the direct neighbors 53 | self.M[wd] = dict.fromkeys(self.variants(wd, self.words), 1) 54 | return self.M[wd] 55 | 56 | 57 | def heuristic(self, u, v): 58 | return sum(a!=b for a, b in zip(u, v)) 59 | 60 | 61 | def ladder(self, s, t, h=None): 62 | if h is None: 63 | def h(v): 64 | return self.heuristic(v, t) 65 | 66 | _, P = a_star(self, s, t, h) 67 | if P is None: 68 | return [s, None, t] 69 | 70 | u, p = t, [] 71 | while u is not None: # Get path to target 72 | p.append(u) 73 | u = P[u] 74 | 75 | p.reverse() # The path is backward 76 | return p 77 | 78 | 79 | if __name__ == '__main__': 80 | wds = set(line.strip().lower() for line in open("/usr/share/dict/words")) 81 | G = WordNeighbors(wds) 82 | print G.ladder('lead', 'gold') 83 | print G.ladder('teamwork', 'vacation') 84 | print G.ladder('axe', 'pie') 85 | print G.ladder('axe', 'pie', h = lambda v: 0) 86 | print counter, G.ladder('camera', 'harder') 87 | print counter, G.ladder('camera', 'harder', h = lambda v: 0) 88 | -------------------------------------------------------------------------------- /tail.origin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import os 4 | import sys 5 | 6 | NUM_LINES = 10 7 | 8 | if __name__ == '__main__': 9 | 10 | with open(sys.argv[1]) as f: 11 | line_ends_seen = 0 12 | chunk_size = 4096 13 | remaining_bytes = os.stat(sys.argv[1]).st_size 14 | 15 | while remaining_bytes: 16 | if chunk_size < remaining_bytes: 17 | remaining_bytes -= chunk_size 18 | else: 19 | chunk_size = remaining_bytes 20 | remaining_bytes = 0 21 | f.seek(remaining_bytes); 22 | chunk = f.read(chunk_size); 23 | i = chunk_size 24 | while line_ends_seen <= NUM_LINES: 25 | i -= 1 26 | if i < 0: break 27 | if chunk[i] == '\n': 28 | line_ends_seen += 1 29 | if line_ends_seen > NUM_LINES: break 30 | #sys.stdout.write(chunk[i+1:]) 31 | f.seek(remaining_bytes+i+1) 32 | while True: 33 | chunk = f.read(chunk_size) 34 | if chunk: 35 | sys.stdout.write(chunk) 36 | else: 37 | break 38 | -------------------------------------------------------------------------------- /tail.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import collections 4 | import os 5 | import sys 6 | 7 | BUF_SIZE = 4096 8 | 9 | def Tail(file, num_lines = 10): 10 | with open(file) as f: 11 | lines_already_found = 0 12 | buffer_size = BUF_SIZE 13 | file_length = os.stat(file).st_size 14 | remain_length = file_length 15 | 16 | while remain_length: 17 | if buffer_size < remain_length: 18 | remain_length -= buffer_size 19 | else: 20 | buffer_size = remain_length 21 | remain_length = 0 22 | 23 | f.seek(remain_length) 24 | data = f.read(buffer_size) 25 | i = buffer_size 26 | while lines_already_found <= num_lines: 27 | i -= 1 28 | if i < 0: 29 | break 30 | if data[i] == '\n': 31 | lines_already_found += 1 32 | if lines_already_found == num_lines + 1: 33 | break 34 | 35 | f.seek(remain_length + i + 1) 36 | while True: 37 | data = f.read(BUF_SIZE) 38 | if data: 39 | sys.stdout.write(data) 40 | else: 41 | break 42 | 43 | """Comments in master""" 44 | """This is comments in experimental.""" 45 | 46 | def Tail2(file, num_lines= 10): 47 | with open(file) as f: 48 | d = collections.deque(f, 10) 49 | for item in d: 50 | sys.stdout.write(item) 51 | 52 | if __name__ == '__main__': 53 | Tail2(sys.argv[1]) 54 | -------------------------------------------------------------------------------- /uniq_chars.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Can extend to unique words, duplicate words etc. 4 | # 5 | 6 | import sys 7 | 8 | def IsUnique(string): 9 | d = {} 10 | for char in string: 11 | if char in d: 12 | return False 13 | else: 14 | d[char] = True 15 | return True 16 | 17 | if __name__ == '__main__': 18 | string = sys.argv[1] 19 | if IsUnique(string): 20 | print 'Is Unique!' 21 | else: 22 | print 'Not Unique!' 23 | --------------------------------------------------------------------------------