├── .gitignore ├── LICENSE ├── README.md ├── dataStructure ├── LRU │ ├── allOne.py │ ├── lru_allone.py │ ├── lru_orderedDict.py │ └── test_allone.py ├── bTree.py ├── binaryHeap.py ├── binaryTree.py ├── circularQueue.py ├── graph │ ├── adjacentList.py │ ├── directed.py │ └── graph.cc ├── hashTable.py ├── huffman │ ├── huffman.cc │ ├── huffman.pdf │ ├── huffman.tex │ └── huffman.toc ├── insert_remove_getRandom.py ├── intervalTree.py ├── leftHeap.py ├── linkedList.py ├── map.cc ├── polynomial.cpp ├── polynomial.py ├── redBlackTree.py ├── redBlackTree0.py ├── splayTree.py ├── trie │ ├── mapSum.py │ ├── maxXor.py │ └── trie.py ├── unionFindSet.py └── winnerTree.py ├── divideAndConquer └── min_distance_of_n_points.py ├── docs ├── README.md ├── _config.yml ├── algorithm-general.md ├── b-tree.md ├── dft.md ├── fib-heap.md ├── graph.md ├── hashTable.md ├── red-black-tree.md ├── sort.md ├── src │ ├── coin1.jpg │ ├── coin2.jpg │ ├── coin3.jpg │ ├── coin4.jpg │ ├── recursive-tree.jpg │ ├── symbol.jpg │ └── test.jpg ├── string-matching.md └── tree.md ├── dynamicProgramming ├── Vec2d.hs ├── __pycache__ │ └── LCS.cpython-37.pyc ├── last-stone-weight.py ├── lcs.py ├── matrixChainMultiply.py ├── max-len-of-repeated-subarray.py ├── splitStripe.hs ├── splitStripe.py ├── stoneGame.py ├── subarraySum.py └── testVec2d.hs ├── graph ├── cloneGraph.cpp ├── dfs.py └── isBipartGraph.py ├── math ├── README.md ├── dft.py ├── fastPow.py ├── fibonacci │ ├── fibonacci.hs │ ├── fibonacci.py │ └── test.hs ├── numWeight │ ├── addNegaBin.py │ ├── convertWeight.py │ └── nega.py ├── numberTheory │ ├── euler.py │ ├── factor.py │ ├── gcd.py │ ├── hammingDistance.py │ ├── isPrime.py │ ├── modulo_equation.py │ ├── primesLEn.hs │ └── sievePrime.py ├── numericalAnalysis │ ├── README.md │ ├── interplotion.py │ ├── iteration.py │ ├── least_square.py │ ├── linear_equation.py │ ├── numerical_integration.py │ ├── solve-linear-by-iteration.py │ └── vector_norm.py └── permute │ ├── permute_back_track.py │ ├── permute_cantor.c │ ├── permute_divide_and_conquer.py │ └── permute_next_permutation.c ├── parser ├── PL0-compiler │ ├── README.md │ ├── parser.py │ ├── requirements.txt │ ├── src │ │ ├── Declaration_parser_display.pptx │ │ ├── argument_pass.dot │ │ ├── argument_pass.jpg │ │ ├── data_stack.jpg │ │ ├── design.md │ │ ├── design.pdf │ │ ├── display.pptx │ │ ├── elseif_ins_stack.dot │ │ ├── elseif_ins_stack.jpg │ │ ├── return_value.dot │ │ ├── return_value.jpg │ │ ├── while_ins_stack.dot │ │ ├── while_ins_stack.jpg │ │ ├── 编译原理—pl0实验报告.doc │ │ ├── 编译原理—pl0实验报告.pdf │ │ └── 编译原理和技术实践2017.pdf │ ├── test │ │ ├── test_token_scanner.py │ │ └── txt │ │ │ ├── bug.txt │ │ │ ├── closure.txt │ │ │ ├── dowhile.txt │ │ │ ├── expr.txt │ │ │ ├── factorial.txt │ │ │ ├── fibonacci.txt │ │ │ ├── gcd.txt │ │ │ └── switch.txt │ └── token_scanner.py ├── calculator │ ├── calculator.hs │ └── genExpr.py ├── declarationParser │ ├── README.md │ ├── declarationParser.py │ ├── result.jpg │ ├── test.txt │ └── token_scanner.py └── leetcode_examples │ ├── README.md │ ├── brace_expansion.py │ ├── calculator.py │ ├── lisp_expression.py │ └── number_of_atoms.py ├── search ├── Astar.py ├── BFS_knight.hs ├── binary_search.hs ├── bloomFilter.py ├── schedule.py └── work_dispatch.py ├── sort ├── __pycache__ │ ├── quickSort.cpython-35.pyc │ └── select.cpython-37.pyc ├── binaryTree.py ├── heapSort.py ├── quickSort.c ├── quickSort.py ├── radixSort.py ├── select.py └── shellSort.py ├── string ├── KMP.py ├── README.md ├── manacher.py ├── markov.py ├── min-window-substring.py ├── rabin_karp.py ├── rotate.py ├── src │ ├── compare.jpg │ └── general.jpg ├── sunday.py └── wildcard_matching.py └── utils ├── codecogs.py ├── config.py ├── genReadme.py ├── headinfo.py └── tree.py /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.o 3 | *.exe 4 | __pycache__ 5 | !.gitignore 6 | *.out 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | 3 | Copyright (C) 2019 Heqin Zhu 4 | 5 | Everyone is permitted to copy and distribute verbatim or modified 6 | copies of this license document, and changing it is allowed as long 7 | as the name is changed. 8 | 9 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 10 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 11 | 12 | 0. You just DO WHAT THE FUCK YOU WANT TO. 13 | -------------------------------------------------------------------------------- /dataStructure/LRU/lru_allone.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : lru_allone.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2019-05-23 23:50 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | from allOne import allOne 13 | 14 | '''In this implementation, the lru doesn't use some funcs of allOne, 15 | such as dec,addDecNode 16 | ''' 17 | class lru: 18 | def __init__(self, capacity): 19 | self.capacity = capacity 20 | self.allOne = allOne() 21 | self.data = {} 22 | def get(self,key): 23 | if key in self.data: 24 | self.allOne.move_to_end(key) 25 | return self.data[key] 26 | return -1 27 | def put(self,key,value): 28 | if key not in self.data: 29 | if len(self.data)==self.capacity: 30 | k = self.allOne.delMinKey() 31 | if k in self.data: 32 | del self.data[k] 33 | self.data[key]=value 34 | self.allOne.append(key) 35 | else: 36 | self.data[key]=value 37 | self.allOne.move_to_end(key) 38 | 39 | 40 | if __name__ == '__main__': 41 | ops = ["put","put","get","put","get","put","get","get","get"] 42 | data = [[1,1],[2,2],[1],[3,3],[2],[4,4],[1],[3],[4]] 43 | obj = lru(2) 44 | operate = {'get':obj.get,'put':obj.put} 45 | for op, args in zip(ops,data): 46 | print(f'{op}({args}): {operate[op](*args)}\n{obj.data}\n') 47 | 48 | -------------------------------------------------------------------------------- /dataStructure/LRU/lru_orderedDict.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : lru_orderedDict.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2019-05-23 20:13 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | class LRUCache(object): 13 | 14 | def __init__(self, capacity): 15 | self.od, self.cap = collections.OrderedDict(), capacity 16 | 17 | def get(self, key): 18 | if key not in self.od: return -1 19 | self.od.move_to_end(key) 20 | return self.od[key] 21 | 22 | def put(self, key, value): 23 | if key in self.od: del self.od[key] 24 | elif len(self.od) == self.cap: self.od.popitem(False) 25 | self.od[key] = value 26 | -------------------------------------------------------------------------------- /dataStructure/LRU/test_allone.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : testAllOne.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-05-19 23:07 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | from allOne import allOne 14 | from time import time 15 | from random import choice,sample,randint 16 | 17 | class hashMap: 18 | def __init__(self): 19 | self.op = {"inc":self.inc,"dec":self.dec,"getMaxKey":self.getMaxKey,"getMinKey":self.getMinKey} 20 | self.mp={'':0} 21 | def inc(self,key,n=1): 22 | if key in self.mp:self.mp[key]+=n 23 | else:self.mp[key]=n 24 | def dec(self,key,n=1): 25 | if key not in self.mp:return 26 | if self.mp[key]<=n:del self.mp[key] 27 | else: self.mp[key]-=n 28 | def getMinKey(self): 29 | return min(list(self.mp.keys()),key=lambda key:self.mp[key]) 30 | def getMaxKey(self): 31 | return max(list(self.mp.keys()),key=lambda key:self.mp[key]) 32 | 33 | 34 | op_origin = ['inc','dec','getMinKey','getMaxKey']#'getMinKey','getMaxKey','getMinKey','getMaxKey','getMinKey','getMaxKey','getMinKey','getMaxKey'] 35 | ch=list('qwertyuiopasdfghjklzxcvbnm') 36 | keys =[ ''.join(sample(ch,i)) for j in range(10) for i in range(1,20,5)] 37 | 38 | def testCase(n=1000): 39 | ops=[] 40 | data=[] 41 | for i in range(n): 42 | p = randint(0,len(op_origin)-1) 43 | ops.append(op_origin[p]) 44 | if p<2: 45 | data.append([randint(1,5)]) 46 | else:data.append([]) 47 | return ops,data 48 | 49 | def test(repeat=100): 50 | t1,t2=0,0 51 | for i in range(repeat): 52 | obj = allOne() 53 | operate = { 54 | "inc": obj.inc, 55 | "dec": obj.dec, 56 | "getMaxKey": obj.getMaxKey, 57 | "getMinKey": obj.getMinKey 58 | } 59 | hsmp = hashMap() 60 | ops,data = testCase() 61 | t1-=time() 62 | for op,datum in zip(ops,data): 63 | operate[op](*datum) 64 | t1+=time() 65 | 66 | t2-=time() 67 | for op,datum in zip(ops,data): 68 | hsmp.op[op](*datum) 69 | t2+=time() 70 | return t1,t2 71 | 72 | 73 | if __name__=='__main__': 74 | t1,t2= test() 75 | print(f'allOne: {t1}') 76 | print(f'hashmap: {t2}') 77 | -------------------------------------------------------------------------------- /dataStructure/binaryTree.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : binaryTree.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-05-19 23:07 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | from functools import total_ordering 14 | 15 | 16 | @total_ordering 17 | class node: 18 | def __init__(self, val, left=None, right=None, freq=1): 19 | self.val = val 20 | self.left = left 21 | self.right = right 22 | self.freq = freq 23 | 24 | def __lt__(self, nd): 25 | return self.val < nd.val 26 | 27 | def __eq__(self, nd): 28 | return self.val == nd.val 29 | 30 | def __repr__(self): 31 | return 'node({})'.format(self.val) 32 | 33 | 34 | class binaryTree: 35 | def __init__(self): 36 | self.root = None 37 | 38 | def add(self, val): 39 | def _add(nd, newNode): 40 | if nd < newNode: 41 | if nd.right is None: 42 | nd.right = newNode 43 | else: 44 | _add(nd.right, newNode) 45 | elif nd > newNode: 46 | if nd.left is None: 47 | nd.left = newNode 48 | else: 49 | _add(nd.left, newNode) 50 | else: 51 | nd.freq += 1 52 | _add(self.root, node(val)) 53 | 54 | def find(self, val): 55 | prt = self._findPrt(self.root, node(val), None) 56 | if prt.left and prt.left.val == val: 57 | return prt.left 58 | elif prt.right and prt.right.val == val: 59 | return prt.right 60 | else: 61 | return None 62 | 63 | def _findPrt(self, nd, tgt, prt): 64 | if nd == tgt or nd is None: 65 | return prt 66 | elif nd < tgt: 67 | return self._findPrt(nd.right, tgt, nd) 68 | else: 69 | return self._findPrt(nd.left, tgt, nd) 70 | 71 | def delete(self, val): 72 | prt = self._findPrt(self.root, node(val), None) 73 | if prt.left and prt.left.val == val: 74 | l = prt.left 75 | if l.left is None: 76 | prt.left = l.right 77 | elif l.right is None: 78 | prt.left = l.left 79 | else: 80 | nd = l.left 81 | while nd.right is not None: 82 | nd = nd.right 83 | nd.right = l.right 84 | prt.left = l.left 85 | elif prt.right and prt.right.val == val: 86 | r = prt.right 87 | if r.right is None: 88 | prt.right = r.right 89 | elif r.right is None: 90 | prt.right = r.left 91 | else: 92 | nd = r.left 93 | while nd.right is not None: 94 | nd = nd.right 95 | nd.right = r.right 96 | prt.left = r.left 97 | 98 | def preOrder(self): 99 | def _p(nd): 100 | if nd is not None: 101 | print(nd) 102 | _p(nd.left) 103 | _p(nd.right) 104 | _p(self.root) 105 | 106 | 107 | if __name__ == "__main__": 108 | t = binaryTree() 109 | for i in range(10): 110 | t.add((i-4)**2) 111 | t.preOrder() 112 | -------------------------------------------------------------------------------- /dataStructure/circularQueue.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : circularQueue.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2019-04-16 09:41 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | 14 | class MyCircularQueue: 15 | 16 | def __init__(self, k): 17 | """ 18 | Initialize your data structure here. Set the size of the queue to be k. 19 | :type k: int 20 | """ 21 | self.size = k+1 22 | self.data = [0]*self.size 23 | self.head = self.rear = 0 24 | 25 | def enQueue(self, value): 26 | """ 27 | Insert an element into the circular queue. Return true if the operation is successful. 28 | :type value: int 29 | :rtype: bool 30 | """ 31 | if self.isFull(): 32 | return False 33 | self.data[self.rear] = value 34 | self.rear = (self.rear+1) % self.size 35 | return True 36 | 37 | def deQueue(self): 38 | """ 39 | Delete an element from the circular queue. Return true if the operation is successful. 40 | :rtype: bool 41 | """ 42 | if self.isEmpty(): 43 | return False 44 | self.head = (self.head+1) % self.size 45 | return True 46 | 47 | def Front(self): 48 | """ 49 | Get the front item from the queue. 50 | :rtype: int 51 | """ 52 | if self.isEmpty(): 53 | return -1 54 | return self.data[self.head] 55 | 56 | def Rear(self): 57 | """ 58 | Get the last item from the queue. 59 | :rtype: int 60 | """ 61 | if self.isEmpty(): 62 | return -1 63 | return self.data[(self.rear-1) % self.size] 64 | 65 | def isEmpty(self): 66 | """ 67 | Checks whether the circular queue is empty or not. 68 | :rtype: bool 69 | """ 70 | return self.head == self.rear 71 | 72 | def isFull(self): 73 | """ 74 | Checks whether the circular queue is full or not. 75 | :rtype: bool 76 | """ 77 | return (self.head - self.rear) % self.size == 1 78 | 79 | 80 | # Your MyCircularQueue object will be instantiated and called as such: 81 | # obj = MyCircularQueue(k) 82 | # param_1 = obj.enQueue(value) 83 | # param_2 = obj.deQueue() 84 | # param_3 = obj.Front() 85 | # param_4 = obj.Rear() 86 | # param_5 = obj.isEmpty() 87 | # param_6 = obj.isFull() 88 | -------------------------------------------------------------------------------- /dataStructure/hashTable.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : hashTable.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-07-08 16:39 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | 14 | class item: 15 | def __init__(self, key, val, nextItem=None): 16 | self.key = key 17 | self.val = val 18 | self.next = nextItem 19 | 20 | def to(self, it): 21 | self.next = it 22 | 23 | def __eq__(self, it): 24 | '''using keyword ''' 25 | return self.key == it.key 26 | 27 | def __bool__(self): 28 | return self.key is not None 29 | 30 | def __str__(self): 31 | li = [] 32 | nd = self 33 | while nd: 34 | li.append(f'({nd.key}:{nd.val})') 35 | nd = nd.next 36 | return ' -> '.join(li) 37 | 38 | def __repr__(self): 39 | return f'item({self.key},{self.val})' 40 | 41 | 42 | class hashTable: 43 | def __init__(self, size=100): 44 | self.size = size 45 | self.slots = [item(None, None) for i in range(self.size)] 46 | 47 | def __setitem__(self, key, val): 48 | nd = self.slots[self.myhash(key)] 49 | while nd.next: 50 | if nd.key == key: 51 | if nd.val != val: 52 | nd.val = val 53 | return 54 | nd = nd.next 55 | nd.next = item(key, val) 56 | 57 | def myhash(self, key): 58 | if isinstance(key, str): 59 | key = sum(ord(i) for i in key) 60 | if not isinstance(key, int): 61 | key = hash(key) 62 | return key % self.size 63 | 64 | def __iter__(self): 65 | '''when using keyword , such as ' if key in dic', 66 | the dic's __iter__ method will be called,(if hasn't, calls __getitem__ 67 | then ~iterate~ dic's keys to compare whether one equls to the key 68 | ''' 69 | for nd in self.slots: 70 | nd = nd.next 71 | while nd: 72 | yield nd.key 73 | nd = nd.next 74 | 75 | def __getitem__(self, key): 76 | nd = self.slots[self.myhash(key)].next 77 | while nd: 78 | if nd.key == key: 79 | return nd.val 80 | nd = nd.next 81 | raise Exception( 82 | f'[KeyError]: {self.__class__.__name__} has no key {key}') 83 | 84 | def __delitem__(self, key): 85 | '''note that None item and item(None,None) differ with each other, 86 | which means you should take care of them and correctly cop with None item 87 | especially when deleting items 88 | ''' 89 | n = self.myhash(key) 90 | nd = self.slots[n].next 91 | if nd.key == key: 92 | if nd.next is None: 93 | self.slots[n] = item(None, None) # be careful 94 | else: 95 | self.slots[n] = nd.next 96 | return 97 | while nd: 98 | if nd.next is None: 99 | break # necessary 100 | if nd.next.key == key: 101 | nd.next = nd.next.next 102 | nd = nd.next 103 | 104 | def __str__(self): 105 | li = ['\n\n'+'-'*5+'hashTable'+'-'*5] 106 | for i, nd in enumerate(self.slots): 107 | li.append(f'{i}: '+str(nd.next)) 108 | return '\n'.join(li) 109 | 110 | 111 | if __name__ == '__main__': 112 | from random import randint 113 | dic = hashTable(16) 114 | n = 100 115 | li = [1, 2, 5, 40, 324, 123, 6, 22, 18, 34, 50] 116 | print(f'build hashTable using {li}') 117 | for i in li: 118 | dic[i] = '$'+str(i) 119 | print(dic) 120 | for i in [1, 34, 45, 123]: 121 | if i in dic: 122 | print(f'{i} in dic, deleting it') 123 | del dic[i] 124 | else: 125 | print(f'{i} not in dic, ignore it') 126 | print(dic) 127 | print(f'dic[2] is {dic[2]}') 128 | try: 129 | dic[-1] 130 | except Exception as e: 131 | print(e) 132 | -------------------------------------------------------------------------------- /dataStructure/huffman/huffman.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/dataStructure/huffman/huffman.pdf -------------------------------------------------------------------------------- /dataStructure/huffman/huffman.toc: -------------------------------------------------------------------------------- 1 | \contentsline {section}{\numberline {1}需求分析}{2} 2 | \contentsline {paragraph}{1}{2} 3 | \contentsline {paragraph}{2}{2} 4 | \contentsline {paragraph}{3}{2} 5 | \contentsline {paragraph}{4}{2} 6 | \contentsline {paragraph}{5}{2} 7 | \contentsline {section}{\numberline {2}概要设计}{2} 8 | \contentsline {subsection}{\numberline {2.1}结点node}{2} 9 | \contentsline {paragraph}{数据对象}{2} 10 | \contentsline {paragraph}{数据关系}{2} 11 | \contentsline {paragraph}{基本操作}{2} 12 | \contentsline {subparagraph}{node()}{2} 13 | \contentsline {subparagraph}{node( const node\& nd}{2} 14 | \contentsline {subparagraph}{operator<}{2} 15 | \contentsline {subsection}{\numberline {2.2}huffman树}{3} 16 | \contentsline {paragraph}{数据对象}{3} 17 | \contentsline {paragraph}{数据关系}{3} 18 | \contentsline {paragraph}{基本操作}{3} 19 | \contentsline {subparagraph}{huffman( map)}{3} 20 | \contentsline {subparagraph}{encode(string)}{3} 21 | \contentsline {subparagraph}{decode(string)}{3} 22 | \contentsline {subparagraph}{preorder()}{3} 23 | \contentsline {subparagraph}{display}{3} 24 | \contentsline {section}{\numberline {3}详细设计}{3} 25 | \contentsline {subsection}{\numberline {3.1}编码,解码算法}{3} 26 | \contentsline {subsection}{\numberline {3.2}输出进度条}{7} 27 | \contentsline {subsection}{\numberline {3.3}改变文件名}{7} 28 | \contentsline {subsection}{\numberline {3.4}统计信息}{7} 29 | \contentsline {section}{\numberline {4}调试分析}{8} 30 | \contentsline {subsection}{\numberline {4.1}编码信息的存储}{8} 31 | \contentsline {subsection}{\numberline {4.2}最后一个字节}{8} 32 | \contentsline {subsection}{\numberline {4.3}文件名的处理}{8} 33 | \contentsline {section}{\numberline {5}用户手册}{8} 34 | \contentsline {section}{\numberline {6}测试结果}{9} 35 | \contentsline {subsection}{\numberline {6.1}文本文件}{9} 36 | \contentsline {subsection}{\numberline {6.2}二进制文件1}{10} 37 | \contentsline {subsection}{\numberline {6.3}二进制文件2}{11} 38 | -------------------------------------------------------------------------------- /dataStructure/insert_remove_getRandom.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : insert_remove_getRandom.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2019-05-24 10:01 10 | # Description: 11 | insert, remove, getRandom 的摊还时间为 O(1), 12 | 且有重复数据, remove 一次删除一个元素 13 | ####################################################################### 14 | ''' 15 | 16 | 17 | class RandomizedCollection: 18 | def __init__(self): 19 | 20 | self.vals = [] 21 | self.index = {} 22 | 23 | def insert(self, val: int) -> bool: 24 | self.vals.append(val) 25 | if val in self.index: 26 | self.index[val].add(len(self.vals)-1) 27 | return False 28 | else: 29 | self.index[val] = {len(self.vals)-1} 30 | return True 31 | 32 | def removeAll(self, val: int) -> bool: 33 | if val not in self.index: 34 | return False 35 | begin = end = len(self.vals)-len(self.index[val]) 36 | for idx in self.index.pop(val): 37 | if idx < begin: 38 | while self.vals[end] == val: 39 | end += 1 40 | self.vals[idx] = self.vals[end] 41 | self.index[self.vals[idx]].remove(end) 42 | self.index[self.vals[idx]].add(idx) 43 | self.vals = self.vals[:begin] 44 | return True 45 | 46 | def remove(self, val): 47 | if val not in self.index: 48 | return False 49 | last = len(self.vals)-1 50 | idx = self.index[val].pop() 51 | if len(self.index[val]) == 0: 52 | del self.index[val] 53 | if idx != last: 54 | self.vals[idx] = self.vals[last] 55 | self.index[self.vals[idx]].remove(last) 56 | self.index[self.vals[idx]].add(idx) 57 | self.vals.pop() 58 | return True 59 | 60 | def getRandom(self) -> int: 61 | if self.vals: 62 | return self.vals[random.randint(0, len(self.vals)-1)] 63 | -------------------------------------------------------------------------------- /dataStructure/intervalTree.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : intervalTree.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-11-18 10:48 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | from random import randint, shuffle 13 | from redBlackTree import redBlackTree 14 | 15 | from functools import total_ordering 16 | 17 | 18 | @total_ordering 19 | class node: 20 | def __init__(self, low, high, left=None, right=None, isBlack=False): 21 | self.val = low # self.val is the low 22 | self.high = high 23 | self.max = high 24 | self.left = left 25 | self.right = right 26 | self.parent = None 27 | self.isBlack = isBlack 28 | 29 | def __lt__(self, nd): 30 | return self.val < nd.val 31 | 32 | def __eq__(self, nd): 33 | return nd is not None and self.val == nd.val 34 | 35 | def setChild(self, nd, isLeft=True): 36 | if isLeft: 37 | self.left = nd 38 | else: 39 | self.right = nd 40 | if nd is not None: 41 | nd.parent = self 42 | 43 | def getChild(self, isLeft): 44 | if isLeft: 45 | return self.left 46 | else: 47 | return self.right 48 | 49 | def __bool__(self): 50 | return self.val is not None 51 | 52 | def __str__(self): 53 | color = 'B' if self.isBlack else 'R' 54 | return f'{color}[{self.val},{self.high}]-{self.max}' 55 | 56 | def __repr__(self): 57 | return f'intervalNode({self.val},{self.high},{self.max},isBlack={self.isBlack})' 58 | 59 | def overlap(self, low, high): 60 | return self.val <= high and self.high >= low 61 | 62 | def setMax(self): 63 | l = 0 if self.left is None else self.left.max 64 | r = 0 if self.right is None else self.right.max 65 | self.max = max(self.high, l, r) 66 | return self.max 67 | 68 | 69 | class intervalTree(redBlackTree): 70 | def search(self, low, high): 71 | nd = self.root 72 | while nd is not None and not nd.overlap(low, high): 73 | if nd.left is not None and nd.left.max >= low: 74 | nd = nd.left 75 | else: 76 | nd = nd.right 77 | return nd 78 | 79 | def insert(self, nd): 80 | super(intervalTree, self).insert(nd) 81 | while nd is not None: 82 | nd.setMax() 83 | nd = nd.parent 84 | 85 | def delete(self, val): 86 | nd = self.find(val) 87 | if nd is not None: 88 | nd.max = 0 89 | tmp = nd.parent 90 | while tmp is not None: 91 | tmp.setMax() 92 | tmp = tmp.parent 93 | super(intervalTree, self).delete(val) 94 | 95 | def rotate(self, prt, chd): 96 | '''rotate prt, and return new prt, namyly the original chd''' 97 | super(intervalTree, self).rotate(prt, chd) 98 | prt.setMax() 99 | chd.setMax() 100 | 101 | def copyNode(self, src, des): 102 | des.val = src.val 103 | des.high = src.high 104 | des.setMax() 105 | 106 | 107 | def genNum(n=10, upper=10): 108 | nums = {} 109 | for i in range(n): 110 | while 1: 111 | d = randint(0, 100) 112 | if d not in nums: 113 | nums[d] = (d, randint(d, d+upper)) 114 | break 115 | return nums.values() 116 | 117 | 118 | def buildTree(n=10, nums=None, visitor=None): 119 | #if nums is None or nums ==[]: nums = genNum(n) 120 | tree = intervalTree() 121 | print(f'build a red-black tree using {nums}') 122 | for i in nums: 123 | tree.insert(node(*i)) 124 | if visitor: 125 | visitor(tree, i) 126 | return tree, nums 127 | 128 | 129 | def testInsert(nums=None): 130 | def visitor(t, val): 131 | print('inserting', val) 132 | print(t) 133 | tree, nums = buildTree(visitor=visitor, nums=nums) 134 | print('-'*5 + 'in-order visit' + '-'*5) 135 | for i, j in enumerate(tree.sort()): 136 | print(f'{i+1}: {j}') 137 | return tree 138 | 139 | 140 | def testSuc(nums=None): 141 | tree, nums = buildTree(nums=nums) 142 | for i in tree.sort(): 143 | print(f'{i}\'s suc is {tree.getSuccessor(i)}') 144 | 145 | 146 | def testDelete(nums=None): 147 | tree, nums = buildTree(nums=nums) 148 | print(tree) 149 | for i in nums: 150 | print(f'deleting {i}') 151 | tree.delete(i[0]) 152 | print(tree) 153 | return tree 154 | 155 | 156 | if __name__ == '__main__': 157 | lst = [(0, 3), (5, 8), (6, 10), (26, 26), (25, 30), 158 | (8, 9), (19, 20), (15, 23), (16, 21), (17, 19)] 159 | #lst = None 160 | # testSuc(lst) 161 | tree = testInsert(lst) 162 | #tree,_= buildTree(lst) 163 | while 1: 164 | a = int(input('low:')) 165 | b = int(input('high:')) 166 | res = tree.search(a, b) 167 | print(res) 168 | -------------------------------------------------------------------------------- /dataStructure/linkedList.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : linkedList.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2019-04-16 09:41 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | 14 | class node: 15 | def __init__(self, val, follow=None): 16 | self.val = val 17 | self.follow = follow 18 | 19 | 20 | class MyLinkedList: 21 | 22 | def __init__(self): 23 | """ 24 | Initialize your data structure here. 25 | """ 26 | 27 | self.tail = self.head = node(None) 28 | 29 | def get(self, index): 30 | """ 31 | Get the value of the index-th node in the linked list. If the index is invalid, return -1. 32 | :type index: int 33 | :rtype: int 34 | """ 35 | nd = self.head 36 | for i in range(index+1): 37 | nd = nd.follow 38 | if nd is None: 39 | return -1 40 | return nd.val 41 | 42 | def addAtHead(self, val): 43 | """ 44 | Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. 45 | :type val: int 46 | :rtype: void 47 | """ 48 | nd = node(val, self.head.follow) 49 | self.head .follow = nd 50 | if self.tail.val is None: 51 | self.tail = nd 52 | 53 | def addAtTail(self, val): 54 | """ 55 | Append a node of value val to the last element of the linked list. 56 | :type val: int 57 | :rtype: void 58 | """ 59 | self.tail.follow = node(val) 60 | self.tail = self.tail.follow 61 | 62 | def addAtIndex(self, index, val): 63 | """ 64 | Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. 65 | :type index: int 66 | :type val: int 67 | :rtype: void 68 | """ 69 | nd = self.head 70 | for i in range(index): 71 | nd = nd.follow 72 | if nd is None: 73 | return 74 | new = node(val, nd.follow) 75 | nd.follow = new 76 | if self.tail == nd: 77 | self.tail = new 78 | 79 | def deleteAtIndex(self, index): 80 | """ 81 | Delete the index-th node in the linked list, if the index is valid. 82 | :type index: int 83 | :rtype: void 84 | """ 85 | nd = self.head 86 | for i in range(index): 87 | nd = nd.follow 88 | if nd is None: 89 | return 90 | if self.tail == nd.follow: 91 | self.tail = nd 92 | if nd.follow: 93 | nd.follow = nd.follow.follow 94 | 95 | 96 | # Your MyLinkedList object will be instantiated and called as such: 97 | # obj = MyLinkedList() 98 | # param_1 = obj.get(index) 99 | # obj.addAtHead(val) 100 | # obj.addAtTail(val) 101 | # obj.addAtIndex(index,val) 102 | # obj.deleteAtIndex(index) 103 | -------------------------------------------------------------------------------- /dataStructure/map.cc: -------------------------------------------------------------------------------- 1 | /* mbinary 2 | ######################################################################### 3 | # File : map.cc 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-04-26 10:33 9 | # Description: 10 | ######################################################################### 11 | */ 12 | 13 | #include 14 | bool isZero(float a) 15 | { 16 | return a < 0.00001 && -a < 0.00001; 17 | } 18 | template class map; 19 | //notice that if you declare a class template,declare the class first like this. 20 | template 21 | class pair 22 | { 23 | friend class map; 24 | pair *next; 25 | public: 26 | t1 first; 27 | t2 second; 28 | 29 | }; 30 | template 31 | class map 32 | { 33 | int n; 34 | pair head; 35 | int cur; 36 | pair *last_visit; 37 | public: 38 | map(); 39 | ~map(); 40 | bool has(t1); 41 | void erase(t1); 42 | t2& operator[](t1); 43 | pair &locate(int index = -1); 44 | int size(); 45 | }; 46 | template 47 | map::map() 48 | { 49 | n = 0; 50 | cur = -1; 51 | last_visit = &head; 52 | head.next = NULL; 53 | head.first = head.second = 0; 54 | } 55 | template 56 | map::~map() 57 | { 58 | pair *p, *q = &head; 59 | 60 | while (q != NULL) { 61 | p = q->next; 62 | delete q; 63 | q = p; 64 | } 65 | } 66 | template 67 | bool map::has(t1 key) 68 | { 69 | pair *p = head.next; 70 | 71 | for (int i = 0; i < n && p->first <= key; ++i) { 72 | if (isZero(p->first - key)) return 1; 73 | 74 | p = p->next; 75 | } 76 | 77 | return 0; 78 | } 79 | template 80 | pair& map::locate(int index) 81 | { 82 | if (index >= n || index < 0) { 83 | printf("the index is out of range\n"); 84 | return head; 85 | } 86 | 87 | if (cur > index) { 88 | last_visit = &head; 89 | cur = -1; 90 | } 91 | 92 | while (cur < index) { 93 | last_visit = last_visit->next; 94 | ++cur; 95 | } 96 | 97 | return *last_visit; 98 | } 99 | template 100 | int map::size() 101 | { 102 | return n; 103 | } 104 | template 105 | t2& map::operator[](t1 key) 106 | { 107 | pair * p = &head; 108 | 109 | while (p->next != NULL) { 110 | if (isZero(p->next->first - key)) return p->next->second; 111 | else if (p->next->first > key) { 112 | break; 113 | } 114 | 115 | p = p->next; 116 | } 117 | 118 | cur = -1; 119 | last_visit = &head; 120 | pair *tmp = new pair; 121 | tmp ->next = p->next; 122 | tmp->first = key; 123 | p->next = tmp; 124 | ++n; 125 | return tmp->second; 126 | } 127 | template 128 | void map::erase(t1 key) 129 | { 130 | pair *p = &head; 131 | 132 | while (p->next != NULL) { 133 | if (isZero(p->next->first - key)) { 134 | pair *q = p->next; 135 | p->next = p->next->next; 136 | delete q; 137 | --n; 138 | break; 139 | } 140 | 141 | p = p->next; 142 | } 143 | 144 | cur = -1; 145 | last_visit = &head; 146 | } 147 | 148 | 149 | int main() 150 | { 151 | map b; 152 | 153 | for (int i = 0; i < 40; ++i) { 154 | b[i] = i; 155 | 156 | if (i % 3) { 157 | b[i] = 1; 158 | } 159 | 160 | if (i % 2) { 161 | b.erase(i); 162 | } 163 | } 164 | 165 | for (int i = 0; i < b.size(); ++i) { 166 | printf("item %d %g:%g\n", i, b.locate(i).first, b.locate(i).second); 167 | } 168 | 169 | return 0; 170 | } 171 | -------------------------------------------------------------------------------- /dataStructure/trie/mapSum.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : mapSum.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2018-12-14 23:11 10 | # Description: 11 | 实现一个 MapSum 类里的两个方法,insert 和 sum。 12 | 13 | 对于方法 insert,你将得到一对(字符串,整数)的键值对。字符串表示键,整数表示值。如果键已经存在,那么原来的键值对将被替代成新的键值对。 14 | 15 | 对于方法 sum,你将得到一个表示前缀的字符串,你需要返回所有以该前缀开头的键的值的总和。 16 | 17 | 示例 1: 18 | 19 | 输入: insert("apple", 3), 输出: Null 20 | 输入: sum("ap"), 输出: 3 21 | 输入: insert("app", 2), 输出: Null 22 | 输入: sum("ap"), 输出: 5 23 | leetcode-ch:677 https://leetcode-cn.com/problems/map-sum-pairs/ 24 | ####################################################################### 25 | ''' 26 | 27 | class node: 28 | def __init__(self,ch,n=0): 29 | self.ch = ch 30 | self.n = n 31 | self.children={} 32 | def __getitem__(self,ch): 33 | return self.children[ch] 34 | def __setitem__(self,ch,nd): 35 | self.children[ch]=nd 36 | def __len__(self): 37 | return len(self.children) 38 | def __iter__(self): 39 | return iter(self.children.values()) 40 | def __delitem(self,ch): 41 | del self.children[ch] 42 | def __contains__(self,ch): 43 | return ch in self.children 44 | class MapSum: 45 | 46 | def __init__(self): 47 | """ 48 | Initialize your data structure here. 49 | """ 50 | self.root = node('') 51 | 52 | def insert(self, key, val): 53 | """ 54 | :type key: str 55 | :type val: int 56 | :rtype: void 57 | """ 58 | nd = self.root 59 | for i in key: 60 | if i not in nd: 61 | nd[i] = node(i) 62 | nd = nd[i] 63 | nd.n = val 64 | def visit(self,nd): 65 | ret = nd.n 66 | for chd in nd: 67 | ret+=self.visit(chd) 68 | return ret 69 | def sum(self, prefix): 70 | """ 71 | :type prefix: str 72 | :rtype: int 73 | """ 74 | nd = self.root 75 | for ch in prefix: 76 | if ch in nd: 77 | nd = nd[ch] 78 | else:return 0 79 | return self.visit(nd) 80 | 81 | -------------------------------------------------------------------------------- /dataStructure/trie/maxXor.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : maxXor.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2018-12-22 09:51 10 | # Description: 11 | maximum_xor_of_two_numbers_in_an_array: 12 | using trie data structure 13 | O(k*n) where n=length(array),k is the max length of radix of num 14 | ####################################################################### 15 | ''' 16 | 17 | class node: 18 | def __init__(self,key,hasKey = False): 19 | self.key = key 20 | self.hasKey = hasKey 21 | self.children={} 22 | def __getitem__(self,key): 23 | return self.children[key] 24 | def __len__(self): 25 | return len(self.children) 26 | def __setitem__(self,key,val): 27 | self.children[key]=val 28 | def __contains__(self,key): 29 | return key in self.children 30 | class trie: 31 | def __init__(self,maxDepth=32): 32 | self.root=node(None) 33 | self.maxDepth = maxDepth 34 | def add(self,num): 35 | nd = self.root 36 | s = bin(num)[2:].rjust(self.maxDepth,'0') 37 | for n in s: 38 | if n not in nd: 39 | nd[n]=node(n) 40 | nd=nd[n] 41 | def search(self,num): 42 | ret = 0 43 | nd = self.root 44 | s = bin(num)[2:].rjust(self.maxDepth,'0') 45 | for n in s: 46 | # note that it's the flip bit 47 | flip = '1' if n=='0' else '0' 48 | if flip in nd: 49 | ret=ret*2+1 50 | nd=nd[flip] 51 | else: 52 | ret*=2 53 | nd=nd[n] 54 | return ret 55 | 56 | def findMaximumXOR(self, nums): 57 | """ 58 | :type nums: List[int] 59 | :rtype: int 60 | """ 61 | if not nums:return 0 62 | n = len(bin(max(nums)))-1 63 | t = trie(n) 64 | for i in nums:t.add(i) 65 | return max(t.search(i) for i in nums) 66 | 67 | if __name__=='__main__': 68 | from random import randint 69 | nums = [randint(1,int(1e18)) for i in 100] 70 | findMaximumXOR(nums) 71 | -------------------------------------------------------------------------------- /dataStructure/trie/trie.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : trie.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-05-19 23:06 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | class node: 14 | def __init__(self,val = None): 15 | self.val = val 16 | self.isKey = False 17 | self.children = {} 18 | def __getitem__(self,i): 19 | return self.children[i] 20 | def __iter__(self): 21 | return iter(self.children.keys()) 22 | def __setitem__(self,i,x): 23 | self.children[i] = x 24 | def __bool__(self): 25 | return self.children!={} 26 | def __str__(self): 27 | return 'val: '+str(self.val)+'\nchildren: '+' '.join(self.children.keys()) 28 | def __repr__(self): 29 | return str(self) 30 | 31 | class Trie(object): 32 | 33 | def __init__(self): 34 | self.root=node('') 35 | self.dic ={'insert':self.insert,'startsWith':self.startsWith,'search':self.search} 36 | 37 | def insert(self, word): 38 | """ 39 | Inserts a word into the trie. 40 | :type word: str 41 | :rtype: void 42 | """ 43 | if not word:return 44 | nd = self.root 45 | for i in word: 46 | if i in nd: 47 | nd = nd[i] 48 | else: 49 | newNode= node(i) 50 | nd[i] = newNode 51 | nd = newNode 52 | else:nd.isKey = True 53 | def search(self, word,matchAll='.'): 54 | """support matchall function eg, 'p.d' matchs 'pad' , 'pid' 55 | """ 56 | self.matchAll = '.' 57 | return self._search(self.root,word) 58 | def _search(self,nd,word): 59 | for idx,i in enumerate(word): 60 | if i==self.matchAll : 61 | for j in nd: 62 | bl =self._search(nd[j],word[idx+1:]) 63 | if bl:return True 64 | else:return False 65 | if i in nd: 66 | nd = nd[i] 67 | else:return False 68 | else:return nd.isKey 69 | def startsWith(self, prefix): 70 | """ 71 | Returns if there is any word in the trie that starts with the given prefix. 72 | :type prefix: str 73 | :rtype: bool 74 | """ 75 | nd = self.root 76 | for i in prefix: 77 | if i in nd: 78 | nd= nd[i] 79 | else:return False 80 | return True 81 | def display(self): 82 | print('preOrderTraverse data of the Trie') 83 | self.preOrder(self.root,'') 84 | def preOrder(self,root,s): 85 | s=s+root.val 86 | if root.isKey: 87 | print(s) 88 | for i in root: 89 | self.preOrder(root[i],s) 90 | 91 | if __name__=='__main__': 92 | t = Trie() 93 | op = ["insert","insert","insert","insert","insert","insert","search","search","search","search","search","search","search","search","search","startsWith","startsWith","startsWith","startsWith","startsWith","startsWith","startsWith","startsWith","startsWith"] 94 | data = [["app"],["apple"],["beer"],["add"],["jam"],["rental"],["apps"],["app"],["ad"],["applepie"],["rest"],["jan"],["rent"],["beer"],["jam"],["apps"],["app"],["ad"],["applepie"],["rest"],["jan"],["rent"],["beer"],["jam"]] 95 | rsts = [None,None,None,None,None,None,False,True,False,False,False,False,False,True,True,False,True,True,False,False,False,True,True,True] 96 | 97 | for i,datum,rst in zip(op,data,rsts): 98 | if t.dic[i](datum[0]) != rst:print(i,datum[0],rst) 99 | t.display() 100 | -------------------------------------------------------------------------------- /dataStructure/unionFindSet.py: -------------------------------------------------------------------------------- 1 | class unionFindSet: 2 | def __init__(self, S): 3 | self.S = {i: i for i in S} 4 | self.size = {i: 1 for i in S} 5 | 6 | def find(self, x): 7 | if x != self.S[x]: 8 | self.S[x] = self.find(self.S[x]) 9 | return self.S[x] 10 | 11 | def union(self, a, b, key=lambda x: x): 12 | x, y = sorted((self.find(a), self.find(b)), key=key) 13 | self.S[y] = x 14 | if x != y: 15 | self.size[x] += self.size[y] 16 | 17 | def getSize(self, x): 18 | return self.size[self.find(x)] 19 | -------------------------------------------------------------------------------- /dataStructure/winnerTree.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : winnerTree.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-05-19 23:06 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | 14 | class winnerTree: 15 | '''if i self.s else 2*p+self.lowExt-self.n+1 46 | 47 | def arrayToTree(self, i): 48 | return (i+self.offset)//2 if i <= self.lowExt else (i-self.lowExt + self.n-1)//2 49 | 50 | def win(self, a, b): 51 | return a < b if self.reverse else a > b 52 | 53 | def initTree(self, p): 54 | if p >= self.n: 55 | delta = p % 2 # !!! good job notice delta mark the lchild or rchlid 56 | return self.players[self.treeToArray(p//2)+delta] 57 | l = self.initTree(2*p) 58 | r = self.initTree(2*p+1) 59 | self.tree[p] = l if self.win(l, r) else r 60 | return self.tree[p] 61 | 62 | def winner(self): 63 | idx = 1 64 | while 2*idx < self.n: 65 | idx = 2*idx if self.tree[2*idx] == self.tree[idx] else idx*2+1 66 | num = self.treeToArray(idx) 67 | num = num+1 if self.players[num] != self.tree[1] else num 68 | return self.tree[1], num 69 | 70 | def getOppo(self, i, x, p): 71 | oppo = None 72 | if 2*p < self.n: 73 | oppo = self.tree[2*p] 74 | elif i <= self.lowExt: 75 | oppo = self.players[i-1+i % 2*2] 76 | else: 77 | lpl = self.players[2*p+self.lowExt-self.n+1] 78 | oppo = lpl if lpl != x else self.players[2*p+self.lowExt-self.n+2] 79 | return oppo 80 | 81 | def update(self, i, x): 82 | ''' i is 1-indexed which is the num of player 83 | and x is the new val of the player ''' 84 | self.players[i] = x 85 | p = self.arrayToTree(i) 86 | oppo = self.getOppo(i, x, p) 87 | self.tree[p] = x if self.win(x, oppo) else oppo 88 | p = p//2 89 | while p: 90 | l = self.tree[p*2] 91 | r = None 92 | if 2*p+1 < self.n: 93 | r = self.tree[p*2+1] # notice this !!! 94 | else: 95 | r = self.players[2*p+self.lowExt-self.n+1] 96 | self.tree[p] = l if self.win(l, r) else r 97 | p = p//2 98 | 99 | 100 | if __name__ == '__main__': 101 | s = [4, 1, 6, 7, 9, 5234, 0, 2, 7, 4, 123] 102 | t = winnerTree(s) 103 | print(t.players, t.tree) 104 | for i in s: 105 | val, idx = t.winner() 106 | print(val, idx) 107 | t.update(idx, -1) 108 | 109 | 110 | ''' 111 | [0, 4, 1, 6, 7, 9, 5234, 0, 2, 7, 4, 123] [0, 5234, 5234, 123, 7, 5234, 7, 123, 4, 7, 5234] 112 | 5234 6 113 | 123 11 114 | 9 5 115 | 7 4 116 | 7 9 117 | 6 3 118 | 4 1 119 | 4 10 120 | 2 8 121 | 1 2 122 | ''' 123 | -------------------------------------------------------------------------------- /divideAndConquer/min_distance_of_n_points.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : min_distance_of_n_points.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-11-24 22:03 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | from random import randint 13 | from time import time 14 | from functools import total_ordering 15 | 16 | 17 | @total_ordering 18 | class point: 19 | def __init__(self, x, y): 20 | self.x = x 21 | self.y = y 22 | 23 | def __neg__(self): 24 | return pont(-self.x, -self.y) 25 | 26 | def __len__(self): 27 | return self.norm(2) 28 | 29 | def __lt__(self, p): 30 | return self.x < p.x or (self.x == p.x and self.y < p.y) 31 | 32 | def __eq__(self, p): 33 | return self.x == p.x and self.y == p.y 34 | 35 | def __hash__(self): 36 | return hash((self.x, self.y)) 37 | 38 | def __repr__(self): 39 | return 'point({},{})'.format(self.x, self.y) 40 | 41 | def __str__(self): 42 | return self.__repr__() 43 | 44 | def norm(self, n=2): 45 | if n <= 0: 46 | return max(abs(self.x), abs(self.y)) 47 | return (abs(self.x)**n+abs(self.y)**n)**(1/n) 48 | 49 | def distance(self, p): 50 | return ((self.x-p.x)**2+(self.y-p.y)**2)**0.5 51 | 52 | 53 | def minDistance_n2(points): 54 | n = len(points) 55 | if n <= 1: 56 | return 0 57 | p, q = points[:2] 58 | minD = points[0].distance(points[1]) 59 | for i in range(n-1): 60 | for j in range(i+1, n): 61 | d = points[i].distance(points[j]) 62 | if d < minD: 63 | minD = d 64 | p = points[i] 65 | q = points[j] 66 | return minD, p, q 67 | 68 | 69 | def findif(points, f, reverse=False): 70 | n = len(points) 71 | rg = range(n-1, -1, -1) if reverse else range(n) 72 | for i in rg: 73 | if not f(points[i]): 74 | return points[i+1:] if reverse else points[:i] 75 | return points.copy() # note that don't return exactly points, return a copy one 76 | 77 | 78 | def floatEql(f1, f2, epsilon=1e-6): 79 | return abs(f1-f2) < epsilon 80 | 81 | 82 | def minDistance_nlogn(n_points): 83 | def _min(pts): 84 | n = len(pts) 85 | if n == 2: 86 | return pts[0].distance(pts[1]), pts[0], pts[1] 87 | if n == 3: 88 | minD = pts[0].distance(pts[1]) 89 | p, q = pts[0], pts[1] 90 | d2 = pts[2].distance(pts[1]) 91 | if minD > d2: 92 | minD = d2 93 | p, q = pts[1], pts[2] 94 | d2 = pts[0].distance(pts[2]) 95 | if minD > d2: 96 | return d2, pts[0], pts[2] 97 | else: 98 | return minD, p, q 99 | n2 = n//2 100 | mid = (pts[n2].x + pts[n2-1].x)/2 101 | s1 = pts[:n2] 102 | s2 = pts[n2:] 103 | minD, p, q = _min(s1) 104 | d2, p2, q2 = _min(s2) 105 | # print('\n\n',minD,p,q,s1) 106 | # print(d2,p2,q2,s2) 107 | if minD > d2: 108 | minD, p, q = d2, p2, q2 109 | 110 | linePoints = findif(s1, lambda pt: floatEql(pt.x, mid), reverse=True) 111 | linePoints += findif(s2, lambda pt: floatEql(pt.x, mid)) 112 | n = len(linePoints) 113 | if n > 1: 114 | for i in range(1, n): 115 | dis = linePoints[i].y - linePoints[i-1].y 116 | if dis < minD: 117 | minD = dis 118 | p, q = linePoints[i-1], linePoints[i] 119 | leftPoints = findif(s1, lambda pt: pt.x >= mid-minD, reverse=True) 120 | rightPoints = findif(s2, lambda pt: pt.x <= mid+minD) 121 | for lp in leftPoints: 122 | y1, y2 = lp.y-minD, lp.y+minD 123 | for rp in rightPoints: 124 | if y1 < rp.y < y2: 125 | dis = lp.distance(rp) 126 | if dis < minD: 127 | minD = dis 128 | p, q = lp, rp 129 | return minD, p, q 130 | return _min(sorted(n_points)) 131 | 132 | 133 | def test(f=minDistance_n2): 134 | print('\ntest : ', f.__name__) 135 | begin = time() 136 | minD, p, q = f(points) 137 | print('time : {:.6f} s'.format(time()-begin)) 138 | print('result: {:.2f} {} {}\n'.format(minD, p, q)) 139 | 140 | 141 | def genData(n, unique=True): 142 | upper = 1000000 143 | if unique: 144 | points = set() 145 | for i in range(n): 146 | points.add(point(randint(1, upper), randint(1, upper))) 147 | return list(points) 148 | else: 149 | return [point(randint(1, upper), randint(1, upper)) for i in range(n)] 150 | 151 | 152 | if __name__ == '__main__': 153 | n = 1000 154 | points = genData(n, unique=True) 155 | print('min distance of {} points'.format(n)) 156 | # print(sorted(points)) 157 | test(minDistance_n2) 158 | test(minDistance_nlogn) 159 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # 笔记 2 | * [algorithm-general.md](./algorithm-general.html) 3 | * [b-tree.md](./b-tree.html) 4 | * [fib-heap.md](./fib-heap.html) 5 | * [graph.md](./graph.html) 6 | * [hashTable.md](./hashTable.html) 7 | * [red-black-tree.md](./red-black-tree.html) 8 | * [sort.md](./sort.html) 9 | * [tree.md](./tree.html) 10 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /docs/src/coin1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/docs/src/coin1.jpg -------------------------------------------------------------------------------- /docs/src/coin2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/docs/src/coin2.jpg -------------------------------------------------------------------------------- /docs/src/coin3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/docs/src/coin3.jpg -------------------------------------------------------------------------------- /docs/src/coin4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/docs/src/coin4.jpg -------------------------------------------------------------------------------- /docs/src/recursive-tree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/docs/src/recursive-tree.jpg -------------------------------------------------------------------------------- /docs/src/symbol.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/docs/src/symbol.jpg -------------------------------------------------------------------------------- /docs/src/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/docs/src/test.jpg -------------------------------------------------------------------------------- /dynamicProgramming/Vec2d.hs: -------------------------------------------------------------------------------- 1 | module Vec2d 2 | (Vec2d, 3 | getVal, 4 | setVal 5 | ) where 6 | import Data.List (intercalate) 7 | 8 | data Vec2d a = Vec (Int,Int) [a] | Vec2 [[a]] 9 | 10 | instance (Show a)=>Show (Vec2d a) where 11 | show (Vec2 ll) = show2d ll 12 | show (Vec (x,y) lst) = show2d $ slice y lst 13 | 14 | getVal i j (Vec (x,y) lst) = lst !! (i*y+j) 15 | getVal i j (Vec2 ll) = ll !! i !! j 16 | 17 | setVal val i j (Vec (x,y) lst) = 18 | let pos = i*y+j 19 | before = take pos lst 20 | after = drop (pos+1) lst 21 | in Vec (x,y) $before ++ [val] ++ after 22 | 23 | setVAl val i j (Vec2 ll) = 24 | let before = take i ll 25 | origin = ll !! i 26 | new = take j origin ++ [val] ++ drop (j+1) origin 27 | after = drop (i+1) ll 28 | in Vec2 $before ++ [new] ++ after 29 | 30 | show2d::(Show a)=>[[a]]->String 31 | show2d ll = 32 | let str =concat . map (\lst-> show lst ++",\n") $ll -- intercalate ",\n" . map show $ ll 33 | in "Vector 2d: [\n"++str++ "]\n" 34 | 35 | slice n lst 36 | | length lst <= n = [lst] 37 | | otherwise = (take n lst) : (slice n $drop n lst) 38 | 39 | -------------------------------------------------------------------------------- /dynamicProgramming/__pycache__/LCS.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/dynamicProgramming/__pycache__/LCS.cpython-37.pyc -------------------------------------------------------------------------------- /dynamicProgramming/last-stone-weight.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : last-stone-weight.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2019-05-28 23:30 10 | # Description: 11 | leetcode 1049: https://leetcode-cn.com/problems/last-stone-weight-ii/ 12 | 13 | 有一堆石头,每块石头的重量都是正整数。 14 | 15 | 每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下: 16 | 17 | 如果 x == y,那么两块石头都会被完全粉碎; 18 | 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。 19 | 最后,最多只会剩下一块石头。返回此石头最小的可能重量。如果没有石头剩下,就返回 0。 20 | 21 | ####################################################################### 22 | ''' 23 | 24 | 25 | class Solution: 26 | def lastStoneWeightII(self, stones: List[int]) -> int: 27 | sm = sum(stones) 28 | ans = sm//2 29 | dp = [0]*(ans+1) 30 | for x in stones: 31 | for j in range(ans, x-1, -1): 32 | dp[j] = max(dp[j], dp[j-x]+x) 33 | return sm-2*dp[ans] 34 | -------------------------------------------------------------------------------- /dynamicProgramming/lcs.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : lcs.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-08-25 12:00 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | 14 | def lcs(a, b): 15 | '''time: O(mn); space: O(mn)''' 16 | m, n = len(a), len(b) 17 | board = [[[] for i in range(n+1)] for i in range(m+1)] 18 | for i in range(m): 19 | for j in range(n): 20 | if a[i] == b[j]: 21 | board[i+1][j+1] = board[i][j]+[a[i]] 22 | elif len(board[i][j+1]) < len(board[i+1][j]): 23 | board[i+1][j+1] = board[i+1][j] 24 | else: 25 | board[i+1][j+1] = board[i][1+j] 26 | return board[m][n] 27 | 28 | 29 | def lcs2(a, b): 30 | '''time: O(mn); space: O(m)''' 31 | m, n = len(a), len(b) 32 | board = [[] for i in range(n+1)] 33 | for i in range(m): 34 | upperLevel = board[0].copy() 35 | for j in range(n): 36 | tmp = board[j+1].copy() 37 | if a[i] == b[j]: 38 | board[j+1] = upperLevel+[a[i]] 39 | elif len(board[j+1]) < len(board[j]): 40 | board[j+1] = board[j].copy() # copy is needed 41 | upperLevel = tmp 42 | return board[n] 43 | 44 | 45 | if __name__ == '__main__': 46 | a = 'ABCBDAB' 47 | b = 'BDCABA' 48 | print('s1:', a) 49 | print('s2:', b) 50 | while 1: 51 | print('lcs:', lcs2(a, b)) 52 | a = input('s1: ') 53 | b = input('s2: ') 54 | -------------------------------------------------------------------------------- /dynamicProgramming/matrixChainMultiply.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : matrixChainMultiply.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-11-05 19:09 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | def matrixChainMultiply(seq): 13 | '''matrix chain multiply, find the optimalest comb to multiply 14 | eg ABCD, (AB)(CD), A((BC)D) 15 | seq: sequence of matrix's scale, eg [A.row,A.col,B.col,C.col,D.col] 16 | ''' 17 | print(seq) 18 | n = len(seq)-1 19 | mat = [[0]*n for i in range(n)] 20 | mark = [[0]*n for i in range(n)] 21 | for l in range(1,n): 22 | for i in range(n): 23 | j = i+l 24 | if j>=n: continue 25 | mat[i][j] = None 26 | for k in range(i,j): 27 | tmp = mat[i][k]+mat[k+1][j]+seq[i]*seq[k+1]*seq[j+1] 28 | if mat[i][j] is None or mat[i][j]>tmp: 29 | mark[i][j] = k 30 | mat[i][j]= tmp 31 | s= findSolution(mark,0,n-1) 32 | print(s) 33 | return mat[0][n-1] 34 | def findSolution(mark,i,j): 35 | if j==i: return 'M{}'.format(i+1) 36 | if j-i==1: return 'M{} * M{}'.format(j,j+1) 37 | k = mark[i][j] 38 | return '('+findSolution(mark,i,k)+') * ('+findSolution(mark,k+1,j)+')' 39 | 40 | if __name__=='__main__': 41 | seq = [5,10,3,12,5,50,6] 42 | res = matrixChainMultiply(seq) 43 | print(res) 44 | -------------------------------------------------------------------------------- /dynamicProgramming/max-len-of-repeated-subarray.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : max-len-of-repeated-subarray.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2019-05-27 08:25 10 | # Description: 11 | 给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。 12 | ####################################################################### 13 | ''' 14 | 15 | 16 | def findLength(A, B): 17 | n, m = len(A), len(B) 18 | dp = [[0]*(m+1) for i in range(n+1)] 19 | for i in range(1, n+1): 20 | for j in range(1, m+1): 21 | if A[i-1] == B[j-1]: 22 | dp[i][j] = dp[i-1][j-1]+1 23 | return max(max(row) for row in dp) 24 | -------------------------------------------------------------------------------- /dynamicProgramming/splitStripe.hs: -------------------------------------------------------------------------------- 1 | import qualified Data.Map as M 2 | 3 | {- 4 | count function: 5 | There is stripe which length is n, 6 | priceMap contains a map for different length of stripe and its price 7 | then find the maximum price to split the stripe in different shorter stripes 8 | ( including the original length if possible) 9 | -} 10 | 11 | priceMap = M.fromList [(1,1),(2,5),(3,8),(4,9),(5,10),(6,17),(7,17),(8,20),(9,24),(10,30)] 12 | 13 | count n priceMap = _count 1 $M.fromList [(0,0)] 14 | where 15 | end = n+1 16 | _count cur rst 17 | | cur == end = rst 18 | | otherwise = _count (1+cur) (M.insert cur price rst) 19 | where 20 | newRst = M.insert cur (getValue cur priceMap) rst 21 | price = maximum. map getPrice $[0..div cur 2] 22 | getPrice a = (getValue a newRst ) + (getValue (cur-a) newRst) 23 | getValue key mp 24 | | M.member key mp = mp M.! key 25 | | otherwise = 0 26 | -------------------------------------------------------------------------------- /dynamicProgramming/splitStripe.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : splitStripe.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-08-24 17:07 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | ''' 14 | There is stripe which length is n, 15 | priceMap contains a map for different length of stripe and its price 16 | then find the maximum price to split the stripe in different shorter stripes 17 | ( including the original length if possible) 18 | ''' 19 | 20 | 21 | def count(n, prices): 22 | def best(cur): 23 | # note that copying the list or create a new list in the following new_stripes codes 24 | if cur in values: 25 | return values[cur], stripes[cur] 26 | maxPrice = 0 27 | new_stripes = [] 28 | for i, j in prices.items(): 29 | if i <= cur: 30 | p, tmp = best(cur-i) 31 | if maxPrice < p+j: 32 | # if the list is not copyed, create a new list, don't use append 33 | new_stripes = tmp+[i] 34 | maxPrice = p+j 35 | values[cur] = maxPrice 36 | stripes[cur] = new_stripes 37 | return maxPrice, new_stripes 38 | values = {0: 0} 39 | stripes = {0: []} 40 | return best(n) 41 | 42 | 43 | if __name__ == '__main__': 44 | li = [(1, 1), (2, 5), (3, 8), (4, 9), (5, 10), 45 | (6, 17), (7, 17), (8, 20), (9, 24), (10, 30)] 46 | prices = {i: j for i, j in li} 47 | n = 40 48 | 49 | d = {i: count(i, prices) for i in range(n+1)} 50 | for i in range(n+1): 51 | print(i, d[i]) 52 | -------------------------------------------------------------------------------- /dynamicProgramming/stoneGame.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : stoneGame.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2018-12-14 14:32 10 | # Description: 11 | 亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] 。游戏以谁手中的石子最多来决出胜负。石子的总数是奇数,所以没有平局。 12 | 亚历克斯和李轮流进行. 每回合,玩家从行的开始或结束处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止,此时手中石子最多的玩家获胜。 13 | 那么先手一定会赢吗? 是的, 求出先手比后手多的石子数. 14 | leetcode-cn 877: https://leetcode-cn.com/problems/stone-game/ 15 | ####################################################################### 16 | ''' 17 | 18 | 19 | def stoneGame(li): 20 | '''li: list, len(li)%2==0, sum(li)%2==1''' 21 | def f(p,q): 22 | ret = dp[p][q] 23 | if ret is None: 24 | if p+1==q: 25 | ret = abs(li[p]-li[q]) 26 | else: 27 | # max min 28 | # take the first one 29 | n1 = li[p] + min(-li[p+1]+f(p+2,q),-li[q]+f(p+1,q-1)) 30 | # take the last one 31 | n2 = li[q] + min(-li[p]+f(p+1,q-1),-li[q-1]+f(p,q-2)) 32 | ret = max(n1,n2) 33 | dp[p][q] = ret 34 | # print(li[p:q+1],ret) 35 | return ret 36 | n = len(li) 37 | dp = [[None for i in range(n)] for i in range(n)] 38 | return f(0,n-1) 39 | -------------------------------------------------------------------------------- /dynamicProgramming/subarraySum.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : subarraySum.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2020-04-20 16:49 10 | # Description: 子数组累加和 11 | ####################################################################### 12 | ''' 13 | from typing import List 14 | 15 | 16 | def subarraySum(nums: List[int], k: int) -> int: 17 | dic = {0: 1} 18 | sm = 0 19 | count = 0 20 | for i in range(len(nums)): 21 | sm += nums[i] 22 | if((sm-k) in dic): 23 | count += dic[sm-k] 24 | if(sm in dic): 25 | dic[sm] += 1 26 | else: 27 | dic[sm] = 1 28 | return count 29 | -------------------------------------------------------------------------------- /dynamicProgramming/testVec2d.hs: -------------------------------------------------------------------------------- 1 | import Vec2d 2 | main = do 3 | let d=[1..10] 4 | ll = [[(i,j)| i<-[1..5]] | j<-['a'..'g']] 5 | print (Vec (2,5) d) 6 | print (Vec (5,2) d) 7 | print (Vec2 ll) 8 | -------------------------------------------------------------------------------- /graph/cloneGraph.cpp: -------------------------------------------------------------------------------- 1 | /* mbinary 2 | ######################################################################### 3 | # File : cloneGraph.cpp 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2019-04-16 09:41 9 | # Description: 10 | ######################################################################### 11 | */ 12 | class Solution 13 | { 14 | public: 15 | map st; 16 | Node *cloneGraph(Node *node) 17 | { 18 | Node* ret = new Node(node->val, vector()); 19 | st[node] = ret; 20 | 21 | for (auto x : node->neighbors) { 22 | auto p = st.find(x); 23 | 24 | if (p == st.end()) { 25 | ret->neighbors.push_back(cloneGraph(x)); 26 | } else ret->neighbors.push_back(p->second); 27 | } 28 | 29 | return ret; 30 | } 31 | }; 32 | /* 33 | // Definition for a Node. 34 | class Node { 35 | public: 36 | int val; 37 | vector neighbors; 38 | 39 | Node() {} 40 | 41 | Node(int _val, vector _neighbors) { 42 | val = _val; 43 | neighbors = _neighbors; 44 | } 45 | }; 46 | */ 47 | -------------------------------------------------------------------------------- /graph/dfs.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : dfs.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2019-05-27 10:02 10 | # Description: 11 | from leetcode-cn #1048: https://leetcode-cn.com/problems/longest-string-chain/ 12 | 给出一个单词列表,其中每个单词都由小写英文字母组成。 13 | 14 | 如果我们可以在 word1 的任何地方添加一个字母使其变成 word2,那么我们认为 word1 是 word2 的前身。例如,"abc" 是 "abac" 的前身。 15 | 16 | 词链是单词 [word_1, word_2, ..., word_k] 组成的序列,k >= 1,其中 word_1 是 word_2 的前身,word_2 是 word_3 的前身,依此类推。 17 | 18 | 从给定单词列表 words 中选择单词组成词链,返回词链的最长可能长度。 19 | 20 | ####################################################################### 21 | ''' 22 | 23 | 24 | class Solution: 25 | def longestStrChain(self, words: List[str]) -> int: 26 | def isAdj(s1, s2): 27 | if len(s1) > len(s2): 28 | s1, s2 = s2, s1 29 | n1, n2 = len(s1), len(s2) 30 | if n2-n1 != 1: 31 | return False 32 | i = j = 0 33 | flag = False 34 | while i < n1 and j < n2: 35 | if s1[i] != s2[j]: 36 | if flag: 37 | return False 38 | flag = True 39 | j += 1 40 | else: 41 | i += 1 42 | j += 1 43 | return True 44 | 45 | def dfs(begin): 46 | ans = 1 47 | w = words[begin] 48 | n = len(w) 49 | if n+1 in lenDic: 50 | for nd in lenDic[n+1]: 51 | # print(w,words[nd],isAdj(w,words[nd])) 52 | if isAdj(w, words[nd]): 53 | ans = max(ans, 1+dfs(nd)) 54 | return ans 55 | lenDic = {} 56 | for i in range(len(words)): 57 | n = len(words[i]) 58 | if n in lenDic: 59 | lenDic[n].add(i) 60 | else: 61 | lenDic[n] = {i} 62 | 63 | lens = sorted(lenDic) 64 | n = len(lens) 65 | ans = 0 66 | for i in range(n): 67 | if ans < n-i: 68 | for nd in lenDic[lens[i]]: 69 | ans = max(ans, dfs(nd)) 70 | return ans 71 | -------------------------------------------------------------------------------- /graph/isBipartGraph.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : isBipartGraph.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2018-12-21 15:00 10 | # Description: Judge if a graph is bipartite 11 | The theorical idea is to judge whether the graph has a odd-path circle. However, it's hard to implement. 12 | The following codes show a method that colors the nodes by dfs. 13 | ####################################################################### 14 | ''' 15 | 16 | 17 | def isBipartite(self, graph): 18 | """ 19 | :type graph: List[List[int]] 20 | :rtype: bool 21 | """ 22 | n = len(graph) 23 | self.node = graph 24 | self.color = {i: None for i in range(n)} 25 | return all(self.dfs(i, True) for i in range(n) if self.color[i] is None) 26 | 27 | 28 | def dfs(self, n, col=True): 29 | if self.color[n] is None: 30 | self.color[n] = col 31 | return all(self.dfs(i, not col) for i in self.node[n]) 32 | else: 33 | return col == self.color[n] 34 | -------------------------------------------------------------------------------- /math/README.md: -------------------------------------------------------------------------------- 1 | # Number Theory 2 | >See more details on [my blog](https://mbinary.xyz/number-theory.html) 3 | 4 | ## gcd.py 5 | - gcd(a,b) 6 | - xgcd(a,b): return gcd(a,b),x,y, where ax+by = gcd(a,b) 7 | 8 | ## isPrime 9 | - isPrime(n): using Miller-Rabin primalrity test. 10 | - primeSieve 11 | 12 | ## euler.py 13 | - phi(n): euler function 14 | - sigma(n): return the sum of all factors of n 15 | 16 | ## factor.py 17 | - factor(n): return a list of numbers that are the factorization of n 18 | 19 | ## modulo_equation.py 20 | Solving modulo equations 21 | 22 | ```python 23 | solver = solve() 24 | res = solver.solveLinear(3,6,9) 25 | 26 | res = solver.solveHigh(1,8,3,11) 27 | 28 | res = solver.solveGroup([(5,11,2),(3,8,5),(4,1,7)]) 29 | ``` 30 | 31 | # Permutation 32 | 33 | -------------------------------------------------------------------------------- /math/dft.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : fft.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2019-06-11 12:48 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | import numpy as np 13 | 14 | 15 | def _fft_n2(a, invert): 16 | '''O(n^2)''' 17 | N = len(a) 18 | w = np.arange(N) 19 | i = 2j if invert else -2j 20 | m = w.reshape((N, 1)) * w 21 | W = np.exp(m * i * np.pi / N) 22 | return np.concatenate(np.dot(W, a.reshape((N, 23 | 1)))) # important, cannot use * 24 | 25 | 26 | def _fft(a, invert=False): 27 | '''recursion version''' 28 | N = len(a) 29 | if N == 1: 30 | return [a[0]] 31 | elif N & (N - 1) == 0: # O(nlogn), 2^k 32 | even = _fft(a[::2], invert) 33 | odd = _fft(a[1::2], invert) 34 | i = 2j if invert else -2j 35 | factor = np.exp(i * np.pi * np.arange(N // 2) / N) 36 | prod = factor * odd 37 | return np.concatenate([even + prod, even - prod]) 38 | else: 39 | return _fft_n2(a, invert) 40 | 41 | 42 | def _fft2(a, invert=False): 43 | ''' iteration version''' 44 | 45 | def rev(x): 46 | ret = 0 47 | for i in range(r): 48 | ret <<= 1 49 | if x & 1: 50 | ret += 1 51 | x >>= 1 52 | return ret 53 | 54 | N = len(a) 55 | if N & (N - 1) == 0: # O(nlogn), 2^k 56 | r = int(np.log(N)) 57 | c = np.array(a, dtype='complex') 58 | i = 2j if invert else -2j 59 | w = np.exp(i * np.pi / N) 60 | for h in range(r - 1, -1, -1): 61 | p = 2**h 62 | z = w**(N / p / 2) 63 | for k in range(N): 64 | if k % p == k % (2 * p): 65 | c[k], c[k + p] = c[k] + c[k + p], c[k] * z**(k % p) 66 | 67 | return np.asarray([c[rev(i)] for i in range(N)]) 68 | else: # O(n^2) 69 | return _fft_n2(a, invert) 70 | 71 | 72 | def fft(a): 73 | '''fourier[a]''' 74 | n = len(a) 75 | if n == 0: 76 | raise Exception("[Error]: Invalid length: 0") 77 | return _fft(a) 78 | 79 | 80 | def ifft(a): 81 | '''invert fourier[a]''' 82 | n = len(a) 83 | if n == 0: 84 | raise Exception("[Error]: Invalid length: 0") 85 | return _fft(a, True) / n 86 | 87 | 88 | def fft2(arr): 89 | return np.apply_along_axis(fft, 0, 90 | np.apply_along_axis(fft, 1, np.asarray(arr))) 91 | 92 | 93 | def ifft2(arr): 94 | return np.apply_along_axis(ifft, 0, 95 | np.apply_along_axis(ifft, 1, np.asarray(arr))) 96 | 97 | 98 | def test(n=128): 99 | print('\nsequence length:', n) 100 | print('fft') 101 | li = np.random.random(n) 102 | print(np.allclose(fft(li), np.fft.fft(li))) 103 | 104 | print('ifft') 105 | li = np.random.random(n) 106 | print(np.allclose(ifft(li), np.fft.ifft(li))) 107 | 108 | print('fft2') 109 | li = np.random.random(n * n).reshape((n, n)) 110 | print(np.allclose(fft2(li), np.fft.fft2(li))) 111 | 112 | print('ifft2') 113 | li = np.random.random(n * n).reshape((n, n)) 114 | print(np.allclose(ifft2(li), np.fft.ifft2(li))) 115 | 116 | 117 | if __name__ == '__main__': 118 | for i in range(1, 4): 119 | test(i * 16) 120 | -------------------------------------------------------------------------------- /math/fastPow.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : fastPow.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2018-12-17 21:39 10 | # Description: fast power 11 | ####################################################################### 12 | ''' 13 | 14 | 15 | def fastPow(a, n): 16 | '''a^n''' 17 | rst = 1 18 | while n: 19 | if n % 2: 20 | rst *= a 21 | n >>= 1 22 | a *= a 23 | return rst 24 | 25 | 26 | def fastMul(a, b): 27 | '''a*b''' 28 | rst = 0 29 | while b: 30 | if b & 1: 31 | rst += a 32 | b >>= 1 33 | a *= 2 34 | -------------------------------------------------------------------------------- /math/fibonacci/fibonacci.hs: -------------------------------------------------------------------------------- 1 | {-''' mbinary 2 | ####################################################################### 3 | # File : fibonacci.hs 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.github.io 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2019-02-03 19:42 9 | # Description: matrix pow and fast pow: 10 | calculate big number fibonacci item. for negative item, use f(n) = f(n+2)-f(n+1) 11 | ####################################################################### 12 | -} 13 | module Fibonacci where 14 | 15 | fib :: Integer -> Integer 16 | fib n = let p = if n>0 then n-2 else 2-n 17 | mat = if n>0 then [1,1,1,0] else [0,1,1,-1] 18 | m = matrix_pow mat p 19 | in m!!0+m!!1 20 | 21 | 22 | matrix_pow mat n = if n<=0 then [1,0,0,1] 23 | else let v = if (mod n 2==0) then [1,0,0,1] else mat 24 | m2 = matrix_mul mat mat 25 | remain = matrix_pow m2 (div n 2) 26 | in matrix_mul v remain 27 | 28 | matrix_mul a b = [ a!!0 * b!!0 +a!!1 * b!!2,a!!0 * b!!1 +a!!1 * b!!3,a!!2 * b!!0 +a!!3 * b!!2, a!!2 * b!!1+a!!3 * b!!3] 29 | -------------------------------------------------------------------------------- /math/fibonacci/fibonacci.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : fibonacci.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.github.io 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2019-02-03 19:10 10 | # Description: use matrix and fast pow to calculate big numbr fibonacci value. 11 | ####################################################################### 12 | ''' 13 | 14 | 15 | def fib(n): 16 | """Calculates the nth Fibonacci number""" 17 | mat, p = (1, 1, 1, 0), n-2 18 | if n <= 0: # for negative fib item, use f(n) = f(n+2)-f(n-1) to calculate 19 | mat = (0, 1, 1, -1), 2-n 20 | li = matrix_pow((0, 1, 1, -1), 1-n) 21 | return li[0]+li[1] 22 | 23 | 24 | def matrix_pow(mat, n): 25 | ans = (1, 0, 0, 1) # element matrix 26 | while n > 0: 27 | if n % 2 == 1: 28 | ans = matrix_mul(ans, mat) 29 | n >>= 1 30 | mat = matrix_mul(mat, mat) 31 | return ans 32 | 33 | 34 | def matrix_mul(a, b): 35 | '''a,b are four-item tuple, represent matrix [[a[0],a[1]],[a[2],a[3]]]''' 36 | return a[0]*b[0]+a[1]*b[2], a[0]*b[1]+a[1]*b[3], a[2]*b[0]+a[3]*b[2], a[2]*b[1]+a[3]*b[3] 37 | 38 | 39 | if __name__ == '__main__': 40 | for i in range(-5, 5): 41 | print(i, fib(i)) 42 | -------------------------------------------------------------------------------- /math/fibonacci/test.hs: -------------------------------------------------------------------------------- 1 | module Fibonacci.Test where 2 | import Fibonacci 3 | import Test.QuickCheck 4 | import Test.QuickCheck.All 5 | 6 | 7 | prop_fib :: Int -> Bool 8 | prop_fib x = fib n == 2 9 | main = $(quickCheckAll) 10 | 11 | :{ 12 | prop_fib 0 = fib 0 == 0 13 | prop_fib 1 = fib 1 == 1 14 | prop_fib 2 = fib 2 == 1 15 | prop_fib 3 = fib 3 == 2 16 | prop_fib 5 = fib 5 == 5 17 | prop_fib 5 = fib 5 == 5 18 | prop_fib -6 = fib -6 == -8 19 | prop_fib -96 = fib -96 == -51680708854858323072 20 | prop_fib 2000 = fib 2000 == 4224696333392304878706725602341482782579852840250681098010280137314308584370130707224123599639141511088446087538909603607640194711643596029271983312598737326253555802606991585915229492453904998722256795316982874482472992263901833716778060607011615497886719879858311468870876264597369086722884023654422295243347964480139515349562972087652656069529806499841977448720155612802665404554171717881930324025204312082516817125 21 | :} 22 | 23 | -------------------------------------------------------------------------------- /math/numWeight/addNegaBin.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : addNegaBin.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2019-06-02 22:32 10 | # Description: 11 | 12 | 给出基数为 -2 的两个数 arr1 和 arr2,返回两数相加的结果。 13 | 14 | 数字以 数组形式 给出:数组由若干 0 和 1 组成,按最高有效位到最低有效位的顺序排列。例如,arr = [1,1,0,1] 表示数字 (-2)^3 + (-2)^2 + (-2)^0 = -3。数组形式 的数字也同样不含前导零:以 arr 为例,这意味着要么 arr == [0],要么 arr[0] == 1。 15 | 16 | 返回相同表示形式的 arr1 和 arr2 相加的结果。两数的表示形式为:不含前导零、由若干 0 和 1 组成的数组。 17 | 18 | eg 19 | 输入:arr1 = [1,1,1,1,1], arr2 = [1,0,1] 20 | 输出:[1,0,0,0,0] 21 | 解释:arr1 表示 11,arr2 表示 5,输出表示 16 22 | ####################################################################### 23 | ''' 24 | from nega import nega 25 | 26 | 27 | def addNegaBin(arr1: list, arr2: list) -> list: 28 | if len(arr1) < len(arr2): 29 | arr1, arr2 = arr2, arr1 30 | for i in range(-1, -len(arr2) - 1, -1): 31 | if arr1[i] == 1 and arr2[i] == 1: 32 | arr1[i] = 0 33 | mux = 0 34 | for j in range(i - 1, -len(arr1) - 1, -1): 35 | if arr1[j] == mux: 36 | mux = 1 - mux 37 | arr1[j] = mux 38 | else: 39 | arr1[j] = mux 40 | break 41 | else: 42 | arr1 = [1, 1] + arr1 43 | 44 | elif arr1[i] == 0 and arr2[i] == 1: 45 | arr1[i] = arr2[i] 46 | # print(arr1,arr2,i) 47 | while len(arr1) > 1 and arr1[0] == 0: 48 | arr1.pop(0) 49 | return arr1 50 | 51 | 52 | if __name__ == '__main__': 53 | while 1: 54 | print("input q to quit or input x1 x2: ") 55 | s = input() 56 | if s == 'q': 57 | break 58 | n1, n2 = [int(i) for i in s.split()] 59 | l1, l2 = nega(n1), nega(n2) 60 | print(n1, l1) 61 | print(n2, l2) 62 | print(f'{n1}+{n2}={n1+n2}: {addNegaBin(l1,l2)}') 63 | -------------------------------------------------------------------------------- /math/numWeight/convertWeight.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : num_weight.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-05-19 21:36 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | 14 | def covert(s, basefrom=10, baseto=2): 15 | return d2n(n2d(s, basefrom), baseto) 16 | 17 | 18 | def n2d(s, base=16): 19 | ''' num of base_n(n<36) to decimal''' 20 | dic = {chr(i+ord('0')): i for i in range(10)} 21 | s = s.upper() 22 | if base > 10: 23 | dic.update({chr(i+ord('A')): i+10 for i in range(26)}) 24 | # if base in [16,8,2] : 25 | # p=max(map(s.find,'OBX')) 26 | # s=s[p+1:] #remove prefix of hex or bin or oct 27 | rst = 0 28 | for i in s: 29 | rst = dic[i]+rst*base 30 | return rst 31 | 32 | 33 | def d2n(n, base=16): 34 | ''' num of base_n(n<36) to decimal''' 35 | dic = {i: chr(i+ord('0')) for i in range(10)} 36 | if base > 10: 37 | dic.update({i+10: chr(i+ord('A')) for i in range(26)}) 38 | rst = [] 39 | while n != 0: 40 | i = int(n/base) 41 | rst.append(dic[n-i*base]) 42 | n = i 43 | return ''.join(rst[::-1]) 44 | 45 | 46 | ''' 47 | >>> n2d(str(d2n(4001))) 48 | 4001 49 | >>> d2n(n2d(str(4001)),2) 50 | '100000000000001' 51 | >>> covert('4001',16,2) 52 | '100000000000001' 53 | ''' 54 | -------------------------------------------------------------------------------- /math/numWeight/nega.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : nega.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2019-06-02 23:15 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | 14 | def nega(n: int, base=-2: int)->: list: 15 | '''return list of num, the first is the highest digit''' 16 | if base > -2: 17 | raise Exception( 18 | f"[Error]: invalid base: {base}, base should be no more than -2") 19 | ans = [] 20 | while n: 21 | k = n % base 22 | if k < 0: 23 | k -= base 24 | ans.append(k) 25 | n = (n-k)//base 26 | return ans[::-1] 27 | -------------------------------------------------------------------------------- /math/numberTheory/euler.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : euler.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2018-12-16 10:53 10 | # Description: 11 | euler function: phi(n) 12 | perfect num: \sigma (n) = 2n, \sigma (n) is the sum of all factors of n 13 | eg \sigma (9) = 3+3+9 = 15 14 | ####################################################################### 15 | ''' 16 | from factor import factor 17 | from collections import Counter 18 | from functools import reduce 19 | from operator import mul 20 | 21 | 22 | def phi(n): 23 | st = set(factor(n)) 24 | return round(reduce(mul, (1-1/p for p in st), n)) 25 | 26 | 27 | def sigma(n): 28 | ct = Counter(factor(n)) 29 | return reduce(mul, (round((p**(ct[p]+1)-1)/(p-1)) for p in ct), 1) 30 | 31 | 32 | if __name__ == '__main__': 33 | while 1: 34 | n = int(input('n: ')) 35 | print('phi(n):', phi(n)) 36 | print('sigma(n):', sigma(n)) 37 | -------------------------------------------------------------------------------- /math/numberTheory/factor.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : factorize.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2018-12-16 09:36 10 | # Description: factorization, using pollard's rho algorithm and miller-rabin primality test 11 | ####################################################################### 12 | ''' 13 | 14 | from random import randint 15 | from isPrime import isPrime 16 | from gcd import gcd 17 | 18 | 19 | def factor(n): 20 | '''pollard's rho algorithm''' 21 | if n < 1: 22 | raise Exception('[Error]: {} is less than 1'.format(n)) 23 | if n == 1: 24 | return [] 25 | if isPrime(n): 26 | return [n] 27 | fact = 1 28 | cycle_size = 2 29 | x = x_fixed = 2 30 | c = randint(1, n) 31 | while fact == 1: 32 | for i in range(cycle_size): 33 | if fact > 1: 34 | break 35 | x = (x*x+c) % n 36 | if x == x_fixed: 37 | c = randint(1, n) 38 | continue 39 | fact = gcd(x-x_fixed, n) 40 | cycle_size *= 2 41 | x_fixed = x 42 | return factor(fact)+factor(n//fact) 43 | 44 | 45 | def fact(n): 46 | f = 2 47 | ret = [] 48 | while f*f <= n: 49 | while not n % f: 50 | ret.append(f) 51 | n//f 52 | f += 1 53 | if n > 1: 54 | ret.append(n) 55 | return ret 56 | 57 | 58 | if __name__ == '__main__': 59 | while 1: 60 | n = int(input('n: ')) 61 | print(factor(n)) 62 | -------------------------------------------------------------------------------- /math/numberTheory/gcd.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : gcd.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2018-12-16 10:06 10 | # Description: 11 | ####################################################################### 12 | ''' 13 | 14 | 15 | def gcd(a, b): 16 | while b != 0: 17 | a, b = b, a % b 18 | return a 19 | 20 | 21 | def lcm(a, b): 22 | return int(a*b/gcd(a, b)) 23 | 24 | 25 | def xgcd(a, b): 26 | '''return gcd(a,b), x,y where ax+by=gcd(a,b)''' 27 | if b == 0: 28 | return a, 1, 0 29 | g, x, y = xgcd(b, a % b) 30 | return g, y, x-a//b*y 31 | 32 | 33 | if __name__ == '__main__': 34 | while 1: 35 | a = int(input('a: ')) 36 | b = int(input('b: ')) 37 | print('gcd :', gcd(a, b)) 38 | print('xgcd:', xgcd(a, b)) 39 | -------------------------------------------------------------------------------- /math/numberTheory/hammingDistance.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : hammingDistance.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2018-12-17 17:36 10 | # Description: 11 | hamming distance is the number of different position (or binary bit for number) of two strings. 12 | eg 'abac', 'ab': 2 1010,11 : 3 13 | ####################################################################### 14 | ''' 15 | 16 | 17 | def hammingDistance(a, b): 18 | if isinstance(a, int): 19 | n = a ^ b 20 | ct = 0 21 | while n: 22 | ct += n % 2 23 | n >>= 1 24 | return ct 25 | else: 26 | n, m = len(a), len(b) 27 | ret = 0 28 | for i, j in zip(a, b): 29 | ret += i == j 30 | return ret+abs(n-m) 31 | 32 | 33 | def totalHammingDistance(lst): 34 | '''return sum of any two items(num or lst( str)) in lst''' 35 | length = len(lst) 36 | if length == 0: 37 | return 0 38 | if isinstance(lst[0], int): 39 | bits = [0] * len(bin(max(lst))) 40 | for n in lst: 41 | ct = 0 42 | while n: 43 | if n % 2 == 1: 44 | bits[ct] += 1 45 | ct += 1 46 | n >>= 1 47 | return sum(i*(length-i) for i in bits) 48 | else: 49 | mx = len(max(lst, key=len)) 50 | position = [dict() for i in range(mx)] 51 | for li in lst: 52 | for i, x in enumerate(li): 53 | if x in position[i]: 54 | position[i][x] += 1 55 | else: 56 | position[i][x] = 1 57 | ret = 0 58 | for dic in position: 59 | left = length 60 | for i in dic.values(): 61 | ret += i*(left-i) # key step 62 | left -= i # key step 63 | return ret 64 | -------------------------------------------------------------------------------- /math/numberTheory/isPrime.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : isPrime.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-03-04 21:34 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | from random import randint 13 | 14 | 15 | def quickMulMod(a, b, m): 16 | '''a*b%m, quick''' 17 | ret = 0 18 | while b: 19 | if b & 1: 20 | ret = (a+ret) % m 21 | b //= 2 22 | a = (a+a) % m 23 | return ret 24 | 25 | 26 | def quickPowMod(a, b, m): 27 | '''a^b %m, quick, O(logn)''' 28 | ret = 1 29 | while b: 30 | if b & 1: 31 | ret = quickMulMod(ret, a, m) 32 | b //= 2 33 | a = quickMulMod(a, a, m) 34 | return ret 35 | 36 | 37 | def isPrime(n, t=5): 38 | '''miller rabin primality test, a probability result 39 | t is the number of iteration(witness) 40 | ''' 41 | t = min(n-3, t) 42 | if n < 2: 43 | print('[Error]: {} can\'t be classed with prime or composite'.format(n)) 44 | return 45 | if n == 2: 46 | return True 47 | d = n-1 48 | r = 0 49 | while d % 2 == 0: 50 | r += 1 51 | d //= 2 52 | tested = set() 53 | for i in range(t): 54 | a = randint(2, n-2) 55 | while a in tested: 56 | a = randint(2, n-2) 57 | tested.add(a) 58 | x = quickPowMod(a, d, n) 59 | if x == 1 or x == n-1: 60 | continue # success, 61 | for j in range(r-1): 62 | x = quickMulMod(x, x, n) 63 | if x == n-1: 64 | break 65 | else: 66 | return False 67 | return True 68 | 69 | 70 | ''' 71 | we shouldn't use Fermat's little theory 72 | Namyly: 73 | For a prime p, and any number a where (a,n)=1 74 | a ^(p-1) \equiv 1 (mod p) 75 | 76 | The inverse theorem of it is not True. 77 | 78 | a counter-example: 2^340 \equiv 1 (mod 341), but 341 is a composite 79 | ''' 80 | 81 | 82 | def twoDivideFind(x, li): 83 | a, b = 0, len(li) 84 | while a <= b: 85 | mid = (a+b)//2 86 | if li[mid] < x: 87 | a = mid+1 88 | elif li[mid] > x: 89 | b = mid-1 90 | else: 91 | return mid 92 | return -1 93 | 94 | 95 | if __name__ == '__main__': 96 | n = 100 97 | print('prime numbers below', n) 98 | print([i for i in range(n) if isPrime(i)]) 99 | while 1: 100 | n = int(input('n: ')) 101 | print(isPrime(n)) 102 | -------------------------------------------------------------------------------- /math/numberTheory/modulo_equation.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : modulo_equation.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-3-4 21:14 9 | # Description: 10 | `--` represents modulo symbol 11 | ######################################################################### 12 | ''' 13 | 14 | import re 15 | 16 | from gcd import xgcd 17 | from euler import phi 18 | from isPrime import isPrime 19 | from factor import factor 20 | 21 | 22 | def ind(m, g): 23 | ''' mod m ,primary root g -> {n:indg n}''' 24 | return {j: i for i in range(m-1) 25 | for j in range(m) if (g**i-j) % m == 0} 26 | 27 | 28 | def gs(m, num=100): 29 | '''return list of m's primary roots below num''' 30 | p = phi(m) 31 | mp = factor(p) 32 | checkLst = [p//i for i in mp] 33 | return [i for i in range(2, num) if all((i**n-1) % m != 0 for n in checkLst)] 34 | 35 | 36 | def minG(m): 37 | p = phi(m) 38 | mp = factor(p) 39 | checkLst = [p//i for i in mp] 40 | i = 2 41 | while 1: 42 | if all((i**n-1) % m != 0 for n in checkLst): 43 | return i 44 | i += 1 45 | 46 | 47 | class solve: 48 | def __init__(self, equ=None): 49 | self.linearPat = re.compile(r'\s*(\d+)\s*--\s*(\d+)[\s\(]*mod\s*(\d+)') 50 | self.sol = [] 51 | #self.m = m 52 | #self.ind_mp = ind(m,minG(m)) 53 | 54 | def noSol(self): 55 | print('equation {equ} has no solution'.format(equ=self.equ)) 56 | 57 | def error(self): 58 | print("Error! The divisor m must be postive integer") 59 | 60 | def solveLinear(self, a, b, m): 61 | '''ax--b(mod m): solve linear equation with one unknown 62 | return ([x1,x2,...],m) 63 | ''' 64 | a, b, m = self.check(a, b, m) 65 | g, x, y = xgcd(a, m) 66 | if a*b % g != 0: 67 | self.noSol() 68 | return None 69 | sol = x*b//g 70 | m0 = m//g 71 | sols = [(sol+i*m0) % m for i in range(g)] 72 | print('{}x--{}(mod {}), solution: {} mod {}'.format(a, b, m, sols, m)) 73 | return (sols, m) 74 | 75 | def check(self, a, b, m): 76 | if m <= 0: 77 | self.error() 78 | return None 79 | if a < 0: 80 | a, b = -a, -b # important 81 | if b < 0: 82 | b += -b//m * m 83 | return a, b, m 84 | 85 | def solveHigh(self, a, n, b, m): 86 | ''' ax^n -- b (mod m) ind_mp is a dict of m's {n: indg n}''' 87 | ind_mp = ind(m, minG(m)) 88 | tmp = ind_mp[b] - ind_mp[a] 89 | if tmp < 0: 90 | tmp += m 91 | sol = self.solveLinear(n, tmp, phi(m)) 92 | re_mp = {j: i for i, j in ind_mp.items()} 93 | sols = [re_mp[i] for i in sol[0]] 94 | print('{}x^{}--{}(mod {}), solution: {} mod {}'.format(a, n, b, m, sols, m)) 95 | return sols, m 96 | 97 | def solveGroup(self, tups): 98 | '''tups is a list of tongyu equation groups, like 99 | [(a1,b1,m1),(a2,b2,m2)...] 100 | and, m1,m2... are all primes 101 | ''' 102 | mp = {} 103 | print('solving group of equations: ') 104 | for a, b, m in tups: 105 | print('{}x--{}(mod {})'.format(a, b, m)) 106 | if m in mp: 107 | if mp[m][0]*b != mp[m][1]*a: 108 | self.noSol() 109 | return 110 | else: 111 | mp[m] = (a, b) 112 | product = 1 113 | for i in mp.keys(): 114 | product *= i 115 | sol = [0] 116 | for i in mp: 117 | xs, m = self.solveLinear(product//i*mp[i][0], 1, i) 118 | new = [] 119 | for x in xs: 120 | cur = x*product//i*mp[i][1] 121 | for old in sol: 122 | new.append(old+cur) 123 | sol = new 124 | sol = [i % product for i in sol] 125 | print('final solution: {} mod {}'.format(sol, product)) 126 | return sol, product 127 | 128 | def __call__(self): 129 | s = input('输入同余方程,用--代表同于号,形如3--5(mod 7)代表3x模7同余于5') 130 | li = self.linearPat.findall(s) 131 | li = [(int(a), int(b), int(m)) for a, b, m in li] 132 | print(self.solveLinear(li[0])) 133 | 134 | 135 | if __name__ == '__main__': 136 | solver = solve() 137 | res = solver.solveLinear(3, 6, 9) 138 | print() 139 | res = solver.solveHigh(1, 8, 3, 11) 140 | print() 141 | res = solver.solveGroup([(5, 11, 2), (3, 8, 5), (4, 1, 7)]) 142 | -------------------------------------------------------------------------------- /math/numberTheory/primesLEn.hs: -------------------------------------------------------------------------------- 1 | genPrimes 2= [2] 2 | genPrimes n = let li = genPrimes $n-1 3 | in if all (\x-> mod n x /=0) li then n:li else li 4 | -------------------------------------------------------------------------------- /math/numberTheory/sievePrime.py: -------------------------------------------------------------------------------- 1 | def sievePrime(n): 2 | if n < 2: 3 | return 0 4 | prime = [1] * (n + 1) 5 | prime[0] = prime[1] = 0 6 | for i in range(2, int(n**0.5) + 1): 7 | if prime[i] == 1: 8 | prime[i*i:n + 1:i] = [0]*len(prime[i*i:n + 1:i]) 9 | return [i for i in range(n+1) if prime[i] == 1] 10 | 11 | 12 | class primeSiever: 13 | '''sieve of Eratosthenes, It will be more efficient when judging many times''' 14 | primes = [2, 3, 5, 7, 11, 13] 15 | 16 | def isPrime(self, x): 17 | if x <= primes[-1]: 18 | return twoDivideFind(x, self.primes) 19 | while x > self.primes[-1]: 20 | left = self.primes[-1] 21 | right = (left+1)**2 22 | lst = [] 23 | for i in range(left, right): 24 | for j in self.primes: 25 | if i % j == 0: 26 | break 27 | else: 28 | lst.append(i) 29 | self.primes += lst 30 | return twoDivideFind(x, lst) 31 | 32 | def nPrime(n): 33 | '''return the n-th prime''' 34 | i = n-len(self.primes) 35 | last = self.primes[-1] 36 | for _ in range(i): 37 | while 1: 38 | last += 2 39 | for p in self.primes: 40 | if last % p == 0: 41 | break 42 | else: 43 | self.primes.append(last) 44 | break 45 | return self.primes[n-1] 46 | 47 | 48 | if __name__ == "__main__": 49 | import sys 50 | if len(sys.argv) < 2: 51 | n = 100 52 | else: 53 | n = int(sys.argv[1]) 54 | ans = sievePrime(n) 55 | print(f'primes <= {n}, nums: {len(ans)}') 56 | print(ans) 57 | -------------------------------------------------------------------------------- /math/numericalAnalysis/README.md: -------------------------------------------------------------------------------- 1 | # 计算方法 2 | >一些计算方法的算法,比如插值,拟合 近似计算,解方程组等 3 | 有些功能numpy, sympy可能已经就有,但是为了学习各种计算方法,我就重新写了一遍,主要使用的是numpy的数组,矩阵,sympy的符号运算 4 | 5 | # 需要 6 | * python3 7 | * python modules 8 | - sympy 9 | - numpy 10 | 11 | # 目录说明 12 | ## interplotion 13 | 插值, 有Lagrange插值, Newton插值 14 | ## iteration 15 | 迭代, 二分迭代, 不动点迭代,差商迭代, 弦截法迭代 16 | ## least_square 17 | 最小二乘拟合, 解矛盾方程组 18 | ## linear_equation 19 | 解线性方程组,用到 20 | * doolittle分解 21 | * crout分解 22 | * ldlt分解 23 | * 列主元消元法 24 | ## vector-norm 25 | 计算向量,矩阵的各种范数 26 | ## tongyu_equation 27 | 解同余方程 28 | 29 | 30 | ## LICENCE 31 | [MIT](LICENCE.txt) 32 | 33 | ## 联系我 34 | * mail: 35 | * QQ : 414313516 36 | -------------------------------------------------------------------------------- /math/numericalAnalysis/interplotion.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : interplotion.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-10-02 21:14 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | ######################################################################### 14 | # File : interplotion.py 15 | # Author: mbinary 16 | # Mail: zhuheqin1@gmail.com 17 | # Blog: https://mbinary.xyz 18 | # Github: https://github.com/mbinary 19 | # Created Time: 2018-05-18 09:29 20 | # Description: 插值计算,有牛顿插值,拉格朗日插值,以及通过插值得到的多项式估计新的函数值 21 | ######################################################################### 22 | 23 | 24 | import sympy 25 | from collections import namedtuple 26 | from functools import reduce 27 | from operator import mul 28 | 29 | X = sympy.Symbol('x') 30 | point = namedtuple('point', ['x', 'y']) 31 | 32 | 33 | class interplotion: 34 | def __init__(self, points): 35 | self.points = [point(x, y) for x, y in points] 36 | self.xs = [i for i, j in points] 37 | self.poly, self.rem = self.newton(self.points, 0, len(self.points)-1) 38 | 39 | def newton(self, li, a, b): 40 | '''li:[(x,f(x))...]''' 41 | 42 | qs = [li[0].y] 43 | 44 | def quoDiff(begin, end): 45 | if begin == end: 46 | return li[begin].y 47 | q = (quoDiff(begin+1, end)-quoDiff(begin, end-1)) / \ 48 | (li[end].x-li[begin].x) 49 | if begin == a: 50 | qs.append(q) 51 | return q 52 | 53 | quoDiff(a, b) 54 | poly, base = 0, 1 55 | for i, q in enumerate(qs): 56 | poly += q*base 57 | base *= X-li[i].x 58 | return poly, base*qs[-1] 59 | 60 | def lagrange(self, points=None): 61 | xs = None 62 | if points is None: 63 | xs = self.xs 64 | points = self.points 65 | else: 66 | xs = [x for x, y in points] 67 | product = reduce(mul, [X-x for x in xs], 1) 68 | poly = 0 69 | for x, y in points: 70 | tmp = product/(X-x) 71 | coef = y/(tmp.subs(X, x)) 72 | poly += coef * tmp 73 | return poly 74 | 75 | def predict(self, val, poly=None): 76 | if poly is None: 77 | poly = self.poly 78 | return poly.subs(X, val) # note the func subs 79 | 80 | 81 | if __name__ == '__main__': 82 | f = interplotion([(81, 9), (100, 10), (121, 11)]) 83 | p = f.lagrange() 84 | print(p.subs(X, 105)) 85 | print(p) 86 | 87 | intor = interplotion([(0, 11), (0.02, 9), (0.04, 7), (0.06, 10)]) 88 | p = intor.lagrange() 89 | print(p) 90 | res = intor.predict(0.08) 91 | print(res) 92 | -------------------------------------------------------------------------------- /math/numericalAnalysis/iteration.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : iteration.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-10-02 21:14 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | import sympy 14 | import numpy as np 15 | from math import sqrt 16 | 17 | 18 | def newton(y: sympy.core, x0: float, epsilon: float = 0.00001, maxtime: int = 50) ->(list, list): 19 | ''' 20 | newton 's iteration method for finding a zeropoint of a func 21 | y is the func, x0 is the init x val: int float epsilon is the accurrency 22 | ''' 23 | if epsilon < 0: 24 | epsilon = -epsilon 25 | ct = 0 26 | t = y.free_symbols 27 | varsymbol = 'x' if len(t) == 0 else t.pop() 28 | x0 = float(x0) 29 | y_diff = y.diff() 30 | li = [x0] 31 | vals = [] 32 | while 1: 33 | val = y.subs(varsymbol, x0) 34 | vals.append(val) 35 | x = x0 - val/y_diff.subs(varsymbol, x0) 36 | li.append(x) 37 | ct += 1 38 | if ct > maxtime: 39 | print("after iteration for {} times, I still havn't reach the accurrency.\ 40 | Maybe this function havsn't zeropoint\n".format(ct)) 41 | return li, val 42 | if abs(x-x0) < epsilon: 43 | return li, vals 44 | x0 = x 45 | 46 | 47 | def secant(y: sympy.core, x0: float, x1: float, epsilon: float = 0.00001, maxtime: int = 50) ->(list, list): 48 | ''' 49 | 弦截法, 使用newton 差商计算,每次只需计算一次f(x) 50 | secant method for finding a zeropoint of a func 51 | y is the func , x0 is the init x val, epsilon is the accurrency 52 | ''' 53 | if epsilon < 0: 54 | epsilon = -epsilon 55 | ct = 0 56 | x0, x1 = float(x0), float(x1) 57 | li = [x0, x1] 58 | t = y.free_symbols 59 | varsymbol = 'x' if len(t) == 0 else t.pop() 60 | last = y.subs(varsymbol, x0) 61 | vals = [last] 62 | while 1: 63 | cur = y.subs(varsymbol, x1) 64 | vals.append(cur) 65 | x = x1-cur*(x1-x0)/(cur-last) 66 | x0, x1 = x1, x 67 | last = cur 68 | li.append(x) 69 | ct += 1 70 | if ct > maxtime: 71 | print("after iteration for {} times, I still havn't reach the accurrency.\ 72 | Maybe this function havsn't zeropoint\n".format(ct)) 73 | return li, vals 74 | if abs(x0-x1) < epsilon: 75 | return li, vals 76 | x0 = x 77 | 78 | 79 | def solveNonlinearEquations(funcs: [sympy.core], init_dic: dict, epsilon: float = 0.001, maxtime: int = 50)->dict: 80 | '''solve nonlinear equations:''' 81 | li = list(init_dic.keys()) 82 | delta = {i: 0 for i in li} 83 | ct = 0 84 | while 1: 85 | ys = np.array([f.subs(init_dic) for f in funcs], dtype='float') 86 | mat = np.matrix([[i.diff(x).subs(init_dic) for x in li] 87 | for i in funcs], dtype='float') 88 | delt = np.linalg.solve(mat, -ys) 89 | for i, j in enumerate(delt): 90 | init_dic[li[i]] += j 91 | delta[li[i]] = j 92 | if ct > maxtime: 93 | print("after iteration for {} times, I still havn't reach the accurrency.\ 94 | Maybe this function havsn't zeropoint\n".format(ct)) 95 | return init_dic 96 | if sqrt(sum(i**2 for i in delta.values())) < epsilon: 97 | return init_dic 98 | 99 | 100 | if __name__ == '__main__': 101 | x, y, z = sympy.symbols('x y z') 102 | 103 | res, res2 = newton(x**5-9, 2, 0.01) 104 | print(res, res2) 105 | 106 | res, res2 = secant(x**3-3*x-2, 1, 3, 1e-3) 107 | print(res, res2) 108 | 109 | funcs = [x**2+y**2-1, x**3-y] 110 | init = {x: 0.8, y: 0.6} 111 | res_dic = solveNonlinearEquations(funcs, init, 0.001) 112 | print(res_dic) 113 | -------------------------------------------------------------------------------- /math/numericalAnalysis/least_square.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : least_square.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-10-02 21:14 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | '''************************************************************************* 14 | > File Name: least-square.py 15 | > Author: mbinary 16 | > Mail: zhuheqin1@gmail.com 17 | > Created Time: Sat 07 Apr 2018 09:55:25 PM DST 18 | > Blog: https://mbinary.xyz 19 | > Description: 最小二乘法解线性方程组, 解矛盾方程组 20 | ************************************************************************''' 21 | 22 | 23 | 24 | 25 | import re 26 | import numpy as np 27 | def solveConflitEqualtion(A, y): 28 | '''solve equation like this: Av = y, 29 | A:m*n v:n*1 y:m*1 30 | return vector v 31 | ''' 32 | A = np.matrix(A) 33 | y = np.array(y) 34 | ata = A.T*A 35 | print('AtA') 36 | print(ata) 37 | return np.linalg.solve(ata, A.T*y) # note that is numpy.linalg.solve 38 | 39 | 40 | def solveLinear(point, index): 41 | y = [[i[1]] for i in point] 42 | x = [[i[0]] for i in point] 43 | A = [] 44 | for i in x: 45 | A.append([i[0]**j for j in index]) 46 | res = solveConflitEqualtion(A, y) 47 | print('the solution is : \n', res) 48 | print('namely: ') 49 | items = ['{:.4f}x^{}'.format(res[i, 0], j) for i, j in enumerate(index)] 50 | print('phi(x) = ', ' + '.join(items)) 51 | 52 | 53 | def handleInput(s=None, y=None): 54 | # numPt = re.compile (r'\d*\.{0,1}\d+') 55 | if not s: 56 | s = input('input matrix A:m*n //m>=n\n') 57 | s = s.replace(' ', '') 58 | li = re.findall(r'(\[(\d+)(,(\d+))+\])', s) 59 | li = [parseLst(i[0]) for i in li] 60 | if not y: 61 | y = input('input a vector y:n*1\n') 62 | y = parseLst(y) 63 | print('Equation: Av = y:') 64 | 65 | print('y is as follows: ') 66 | print(y) 67 | print('A is as follows: ') 68 | for i in li: 69 | for j in i: 70 | print('{}'.format(j).rjust(5), end='') 71 | print('') 72 | 73 | print('result v is as follows: ') 74 | res = solveConflitEqualtion(li, y) 75 | print(res) 76 | 77 | 78 | def parseLst(s): 79 | s = s.strip('[]') 80 | li = s.split(',') 81 | li = [float(j) for j in li] 82 | return li 83 | 84 | 85 | if __name__ == '__main__': 86 | ''' 87 | li = '[[23,2],[2,5],[2,6]]' 88 | y = '[1,3]' 89 | while True: 90 | handleInput(li,y) 91 | s = input('input y to continue, n for exit') 92 | if s!='y':break 93 | ''' 94 | point = [(-3, 14.3), (-2, 8.3), (-1, 4.7), (2, -8.3), (4, -22.7)] 95 | lst = [0, 3] 96 | solveLinear(point, lst) 97 | 98 | point = [(-3, 14.3), (-2, 8.3), (-1, 4.7), (2, 8.3), (4, 22.7)] 99 | lst = [0, 2] 100 | solveLinear(point, lst) 101 | 102 | A = [[1, 2], [2, 1], [1, 1]] 103 | y = [[5], [6], [4]] 104 | res = solveConflitEqualtion(A, y) 105 | 106 | print(res) 107 | A = [[1, -2], [1, 5], [2, 1], [1, 1]] 108 | y = [[1], [13.1], [7.9], [5.1]] 109 | print(solveConflitEqualtion(A, y)) 110 | -------------------------------------------------------------------------------- /math/numericalAnalysis/linear_equation.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : linear_equation.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-10-02 21:14 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | #coding: utf-8 14 | '''************************************************************************ 15 | > File Name: doolittle.py 16 | > Author: mbinary 17 | > Mail: zhuheqin1@gmail.com 18 | > Blog: https://mbinary.xyz 19 | > Created Time: 2018-04-20 08:32 20 | ************************************************************************''' 21 | 22 | 23 | 24 | 25 | import numpy as np 26 | def getLU(A): 27 | '''doolittle : A = LU, 28 | L is in down-triangle form, 29 | U is in up-triangle form 30 | ''' 31 | m, n = A.shape 32 | if m != n: 33 | raise Exception("this matrix is not inversable") 34 | 35 | L = np.zeros([m, m]) 36 | U = np.zeros([m, m]) 37 | L = np.matrix(L) 38 | U = np. matrix(U) 39 | U[0] = A[0] 40 | L[:, 0] = A[:, 0] / A[0, 0] 41 | for i in range(1, m): 42 | for j in range(i, m): 43 | U[i, j] = A[i, j] - sum(L[i, k]*U[k, j] for k in range(i)) 44 | L[j, i] = (A[j, i] - sum(L[j, k]*U[k, i] 45 | for k in range(i)))/U[i, i] 46 | print(L) 47 | print(U) 48 | return L, U 49 | 50 | 51 | def gauss_prior_elimination(A): 52 | '''using guass elimination,get up_trianglge form of A''' 53 | m, n = A.shape 54 | if m != n: 55 | raise Exception("[Error]: matrix is not inversable") 56 | # necessary,otherwise when the dtype of A is int, then it will be wrong 57 | B = np.matrix(A, dtype=float) 58 | for i in range(m-1): 59 | # note using abs value, return a matrix in (m-i)x1 form 60 | col = abs(B[i:, i]) 61 | mx = col.max() 62 | if mx == 0: 63 | raise Exception("[Error]: matrix is not inversable") 64 | pos = i+col.argmax() 65 | if pos != i: 66 | B[[pos, i], :] = B[[i, pos], :] # note how to swap cols/rows 67 | B[i, :] = 1/mx*B[i, :] 68 | for j in range(i+1, m): 69 | # print(B) 70 | B[j, :] -= B[j, i] * B[i, :] 71 | print(B) 72 | return B 73 | 74 | 75 | def solveDown(A, b): 76 | '''A is a matrix in down-triangle form''' 77 | sol = np.zeros(b.shape) 78 | for i in range(b.shape[0]): 79 | sol[i, 0] = (b[i, 0]-sum(A[i, j]*sol[j, 0] for j in range(i)))/A[i, i] 80 | return sol 81 | 82 | 83 | def solveUp(A, b): 84 | '''A is a matrix in up-triangle form''' 85 | sol = np.zeros(b.shape) 86 | n = b.shape[0] 87 | for i in range(n-1, -1, -1): 88 | sol[i, 0] = (b[i, 0]-sum(A[i, j]*sol[j, 0] 89 | for j in range(n-1, i, -1)))/A[i, i] 90 | return sol 91 | 92 | 93 | def doolittle(A, b): 94 | L, U = getLU(A) 95 | y = solveDown(L, b) 96 | x = solveUp(U, y) 97 | print(y) 98 | print(x) 99 | return x 100 | 101 | 102 | def ldlt(A, b): 103 | L, U = getLU(A) 104 | D = np.diag(np.diag(U)) 105 | print(D, "D") 106 | z = np.linalg.solve(L, b) 107 | print(z, "z") 108 | y = np.linalg.solve(D, z) 109 | print(y, "y") 110 | x = np.linalg.solve(L.T, y) 111 | print(x, "x") 112 | return x 113 | 114 | 115 | if __name__ == '__main__': 116 | A = np.matrix([[10, 5, 0, 0], 117 | [2, 2, 1, 0], 118 | [0, 10, 0, 5], 119 | [0, 0, 2, 1]]) 120 | b = np.matrix([[5], [3], [27], [6]]) 121 | gauss_prior_elimination(A) 122 | 123 | '''ldlt 124 | A = np.matrix([[-6,3,2], 125 | [3,5,1], 126 | [2,1,6]]) 127 | b = np.matrix([[-4],[11],[-8]]) 128 | ldlt(A,b) 129 | ''' 130 | ''' 131 | A = np.matrix([[2,1,1], 132 | [1,3,2], 133 | [1,2,2]]) 134 | b = np.matrix([[4],[6],[5]]) 135 | doolittle(A,b) 136 | ''' 137 | -------------------------------------------------------------------------------- /math/numericalAnalysis/numerical_integration.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : numerical_integration.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-10-02 21:14 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | 14 | ######################################################################### 15 | # File : numerical integration.py 16 | # Author: mbinary 17 | # Mail: zhuheqin1@gmail.com 18 | # Blog: https://mbinary.xyz 19 | # Github: https://github.com/mbinary 20 | # Created Time: 2018-05-11 08:58 21 | # Description: 22 | # numerical intergration: using Newton-Cotes integration, and Simpson 23 | # 数值积分, 使用 牛顿-科特斯积分, 辛普森 24 | ######################################################################### 25 | 26 | 27 | import numpy as np 28 | 29 | 30 | def trapezoidal(a, b, h, fs): 31 | '''梯形积分公式''' 32 | xs = [i for i in np.arange(a, b+h, h)] 33 | print(xs) 34 | ret = h*(sum(fs)-fs[0]/2 - fs[-1]/2) 35 | print(ret) 36 | return ret 37 | 38 | 39 | def simpson(a, b, h, fs): 40 | '''辛普森积分公式''' 41 | xs = [i for i in np.arange(a, b+h, h)] 42 | print(xs) 43 | ret = h/3*(4 * sum(fs[1::2]) + 2*sum(fs[2:-1:2]) + fs[0]+fs[-1]) 44 | print(ret) 45 | return ret 46 | 47 | 48 | def romberg(a, b, f, epcilon): 49 | '''romberg(龙贝格) 数值积分''' 50 | h = b-a 51 | lst1 = [h*(f(a)+f(b))/2] 52 | print(lst1) 53 | delta = epcilon 54 | k = 1 55 | while delta >= epcilon: 56 | h /= 2 57 | k += 1 58 | lst2 = [] 59 | lst2.append((lst1[0]+h*2*sum(f(a+(2*i-1)*h) 60 | for i in range(1, 2**(k-2)+1)))/2) 61 | for j in range(0, k-1): 62 | lst2.append(lst2[j]+(lst2[j]-lst1[j])/(4**(j+1)-1)) 63 | delta = abs(lst2[-1]-lst1[-1]) 64 | lst1 = lst2 65 | print(lst1) 66 | 67 | 68 | if __name__ == '__main__': 69 | a, b, h = 0.6, 1.8, 0.2 70 | fs = [5.7, 4.6, 3.5, 3.7, 4.9, 5.2, 5.5] 71 | trapezoidal(a, b, h, fs) 72 | simpson(a, b, h, fs) 73 | romberg(1, 2, lambda x: sin(x**4), 1e-4) 74 | -------------------------------------------------------------------------------- /math/numericalAnalysis/solve-linear-by-iteration.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : solve-linear-by-iteration.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-10-02 21:14 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | ''' 14 | ######################################################################### 15 | # File : solve-linear-by-iteration.py 16 | # Author: mbinary 17 | # Mail: zhuheqin1@gmail.com 18 | # Blog: https://mbinary.xyz 19 | # Github: https://github.com/mbinary 20 | # Created Time: 2018-05-04 07:42 21 | # Description: 22 | ######################################################################### 23 | ''' 24 | 25 | 26 | 27 | 28 | import numpy as np 29 | from operator import le, lt 30 | def jacob(A, b, x, accuracy=None, times=6): 31 | ''' Ax=b, arg x is the init val, times is the time of iterating''' 32 | A, b, x = np.matrix(A), np.matrix(b), np.matrix(x) 33 | n, m = A.shape 34 | if n != m: 35 | raise Exception("Not square matrix: {A}".format(A=A)) 36 | if b.shape != (n, 1): 37 | raise Exception( 38 | 'Error: {b} must be {n} x1 in dimension'.format(b=b, n=n)) 39 | D = np.diag(np.diag(A)) 40 | DI = np.zeros([n, n]) 41 | for i in range(n): 42 | DI[i, i] = 1/D[i, i] 43 | R = np.eye(n) - DI * A 44 | g = DI * b 45 | print('R =\n{}'.format(R)) 46 | print('g =\n{}'.format(g)) 47 | last = -x 48 | if accuracy != None: 49 | ct = 0 50 | while 1: 51 | ct += 1 52 | tmp = x-last 53 | last = x 54 | mx = max(abs(i) for i in tmp) 55 | if mx < accuracy: 56 | return x 57 | x = R*x+g 58 | print('x{ct} =\n{x}'.format(ct=ct, x=x)) 59 | else: 60 | for i in range(times): 61 | x = R*x+g 62 | print('x{ct} = \n{x}'.format(ct=i+1, x=x)) 63 | print('isLimitd: {}'.format(isLimited(A))) 64 | return x 65 | 66 | 67 | def gauss_seidel(A, b, x, accuracy=None, times=6): 68 | ''' Ax=b, arg x is the init val, times is the time of iterating''' 69 | A, b, x = np.matrix(A), np.matrix(b), np.matrix(x) 70 | n, m = A.shape 71 | if n != m: 72 | raise Exception("Not square matrix: {A}".format(A=A)) 73 | if b.shape != (n, 1): 74 | raise Exception( 75 | 'Error: {b} must be {n} x1 in dimension'.format(b=b, n=n)) 76 | D = np. matrix(np.diag(np.diag(A))) 77 | L = np.tril(A) - D # L = np.triu(D.T) - D 78 | U = np.triu(A) - D 79 | DLI = (D+L).I 80 | S = - (DLI) * U 81 | f = (DLI)*b 82 | print('S =\n{}'.format(S)) 83 | print('f =\n{}'.format(f)) 84 | last = -x 85 | if accuracy != None: 86 | ct = 0 87 | while 1: 88 | ct += 1 89 | tmp = x-last 90 | last = x 91 | mx = max(abs(i) for i in tmp) 92 | if mx < accuracy: 93 | return x 94 | x = S*x+f 95 | print('x{ct} =\n{x}'.format(ct=ct, x=x)) 96 | else: 97 | for i in range(times): 98 | x = S*x+f 99 | print('x{ct} = \n{x}'.format(ct=i+1, x=x)) 100 | print('isLimitd: {}'.format(isLimited(A))) 101 | return x 102 | 103 | 104 | def isLimited(A, strict=False): 105 | '''通过检查A是否是[严格]对角优来判断迭代是否收敛, 即对角线上的值是否都大于对应行(或者列)的值''' 106 | diag = np.diag(A) 107 | op = lt if strict else le 108 | if op(A.max(axis=0), diag).all(): 109 | return True 110 | if op(A.max(axis=1), diag).all(): 111 | return True 112 | return False 113 | 114 | 115 | testcase = [] 116 | 117 | 118 | def test(): 119 | for func, A, b, x, *args in testcase: 120 | acc = None 121 | times = 6 122 | if args != []: 123 | if isinstance(args[0], int): 124 | times = args[0] 125 | else: 126 | acc = args[0] 127 | return func(A, b, x, acc, times) 128 | 129 | 130 | if __name__ == '__main__': 131 | A = [[2, -1, -1], 132 | [1, 5, -1], 133 | [1, 1, 10] 134 | ] 135 | b = [[-5], [8], [11]] 136 | x = [[1], [1], [1]] 137 | # testcase.append([gauss_seidel,A,b,x]) 138 | 139 | A = [[2, -1, 1], [3, 3, 9], [3, 3, 5]] 140 | b = [[-1], [0], [4]] 141 | x = [[0], [0], [0]] 142 | # testcase.append([jacob,A,b,x]) 143 | 144 | A = [[5, -1, -1], 145 | [3, 6, 2], 146 | [1, -1, 2] 147 | ] 148 | b = [[16], [11], [-2]] 149 | x = [[1], [1], [-1]] 150 | testcase.append([gauss_seidel, A, b, x, 0.001]) 151 | test() 152 | -------------------------------------------------------------------------------- /math/numericalAnalysis/vector_norm.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : vector_norm.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-10-02 21:14 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | from random import randint, random 14 | import numpy as np 15 | from operator import neg, and_ 16 | from functools import reduce 17 | 18 | 19 | class obj(): 20 | def __init__(self, data): 21 | self.data = np.array(data) 22 | 23 | def __add__(self, x): 24 | data = x.data if self.__class__ == x.__class__ else x 25 | return self.__class__(self.data + data) 26 | 27 | def __radd__(self, x): 28 | data = x.data if self.__class__ == x.__class__ else x 29 | return self.__class__(data + self.data) 30 | 31 | def __iadd__(self, x): 32 | data = x.data if self.__class__ == x.__class__ else x 33 | self.data += data 34 | 35 | def __mul__(self, x): 36 | data = x.data if self.__class__ == x.__class__ else x 37 | return self.__class__(self.data * data) 38 | 39 | def __imul__(self, x): 40 | data = x.data if self.__class__ == x.__class__ else x 41 | self.data *= data 42 | 43 | def __rmul__(self, x): 44 | data = x.data if self.__class__ == x.__class__ else x 45 | return self.__class__(data * self.data) 46 | 47 | def __neg__(self): 48 | return neg(self) 49 | 50 | def __abs__(self): 51 | return abs(self.data) 52 | ''' 53 | @property 54 | def data(self): 55 | return self.data 56 | @data.setter 57 | def data(self,s): 58 | self.data = s 59 | ''' 60 | 61 | def norm(self, n=0): 62 | '''the default is +oo norm''' 63 | absolute = abs(self.data) 64 | if n < 1: 65 | return max(absolute) 66 | return (sum(absolute**n))**(1/n) 67 | 68 | def hasNorm(self): 69 | '''check norm's three necessary conditions: 70 | 1. not neg 71 | 2. homogenious (qici) 72 | 3. triangle inequlity 73 | 74 | there is much probably wrong 75 | ''' 76 | bl = reduce(and_, [self.norm(i) >= 0 for i in range(3)]) 77 | if bl: 78 | n = randint(2, 100) 79 | bl = reduce(and_, [n*(self.norm(i)) == (n*self).norm(i) 80 | for i in range(3)]) 81 | if bl: 82 | another = self*randint(2, 10)-randint(1, 100) 83 | return reduce(and_, [(another+self).norm(i) <= another.norm(i)+self.norm(i) for i in range(3)]) 84 | return False 85 | 86 | 87 | class vector(obj): 88 | def __init__(self, arr): 89 | ''' arr: iterable''' 90 | self.data = np.array(arr) 91 | 92 | def innerProduct(self, x): 93 | return sum(self.data*x) 94 | 95 | def outerProduct(self, x): 96 | pass 97 | 98 | 99 | class matrix(obj): 100 | def __init__(self, s): 101 | '''s is a list of lists''' 102 | self.data = np.mat(s) 103 | self.T = None 104 | self. I = None 105 | ''' 106 | @property 107 | def T(self): 108 | if self.T==None:self.T = self.data.T 109 | return self.T 110 | @T.setter 111 | def T(self,s): 112 | self.T = s 113 | @property 114 | def I(self): 115 | if self.I == None: self.I = self.data.I 116 | return self.I 117 | 118 | @I.setter 119 | def I(self,s): 120 | self.I = s 121 | ''' 122 | 123 | def E(self, n=None): 124 | if n is None: 125 | n = self.data.shape[0] 126 | return np.eye(n) 127 | 128 | def norm(self, n=0): 129 | absolute = abs(self.data) 130 | if n < 1: 131 | # max of one row sum 132 | return max([sum(i) for i in absolute]) 133 | if n == 1: 134 | return self.norm1() 135 | elif n == 2: 136 | return self.norm2() 137 | 138 | def norm1(self): 139 | ''' max of sum of cols''' 140 | absolute = abs(self.data) 141 | return max(absolute.sum(axis=0)) 142 | 143 | def norm2(self): 144 | ''' max of sum of rows''' 145 | absolute = abs(self.data) 146 | return max(absolute.sum(axis=1)) 147 | 148 | def norm_f(self): 149 | return sum((self.data**2).sum(axis=1))**0.5 150 | 151 | 152 | if __name__ == '__main__': 153 | v1 = vector([1, -2, 3, 4]) 154 | v2 = vector([0, 2, 0, 5]) 155 | m1 = matrix([v1, v2, v2, v1]) 156 | print([v1.norm(i) for i in range(3)]) 157 | -------------------------------------------------------------------------------- /math/permute/permute_back_track.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : permute_back_track.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-11-25 12:32 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | 14 | def permute(n): 15 | def _util(lst, i): 16 | if i == n: 17 | print(lst) 18 | else: 19 | for j in range(i, n): 20 | lst[i], lst[j] = lst[j], lst[i] 21 | _util(lst, i+1) 22 | lst[i], lst[j] = lst[j], lst[i] 23 | _util([i for i in range(n)], 0) 24 | 25 | 26 | if __name__ == '__main__': 27 | permute(5) 28 | -------------------------------------------------------------------------------- /math/permute/permute_cantor.c: -------------------------------------------------------------------------------- 1 | /* mbinary 2 | ######################################################################### 3 | # File : permute_cantor.c 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-11-17 11:25 9 | # Description: 10 | ######################################################################### 11 | */ 12 | #include 13 | 14 | //使用康托展开计算全排列, 下面存储的是0!,1!,2!...(n-1)! 15 | long long int fac[100] = {}; 16 | void calFac(int n) 17 | { 18 | int i; 19 | fac[0] = 1; 20 | 21 | for (i = 1; i <= n; i++) { 22 | fac[i] = i * fac[i - 1]; 23 | } 24 | } 25 | 26 | void permute(int *arr, int n, int sum) 27 | { 28 | /*sum表示全排列由小到大排序后的名次,从0 开始计数, 由名次求出 n位的排列存储到 arr 中*/ 29 | int i, j, ct = 0, k, ct2; 30 | int flag[n]; 31 | 32 | for (i = 0; i < n; i++)flag[i] = 1; 33 | 34 | for (i = n - 1; i >= 0; i--) { 35 | for (j = i; j >= 0; j--) { 36 | if (j * fac[i] <= sum) { 37 | ct2 = 0; 38 | 39 | for (k = 0; k < n; ++k) { 40 | //printf("i%d j%d k%d\n",i,j,k); 41 | if (flag[k] == 1)ct2++; 42 | 43 | if (ct2 > j)break; 44 | } 45 | 46 | arr[ct++] = k; 47 | flag[k] = 0; 48 | sum -= j * fac[i]; 49 | break; 50 | } 51 | } 52 | } 53 | } 54 | 55 | void printArr(int *p, int n) 56 | { 57 | for (int i = 0; i < n; ++i)printf("%d, ", p[i]); 58 | 59 | printf("\n"); 60 | } 61 | 62 | int main() 63 | { 64 | int n = 5, arr[n]; 65 | calFac(n); 66 | 67 | for (int i = 0; i < 5; ++i)arr[i] = i; 68 | 69 | for (int i = 0; i < fac[n]; ++i) { 70 | printArr(arr, n); 71 | permute(arr, n, i); 72 | } 73 | 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /math/permute/permute_divide_and_conquer.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : permute_divide_and_conquer.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-11-25 12:23 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | 14 | def permute(lst, n): 15 | ''' O(n!), optimal''' 16 | if n == 1: 17 | print(lst) 18 | else: 19 | for i in range(n): 20 | lst[i], lst[n-1] = lst[n-1], lst[i] 21 | permute(lst, n-1) 22 | lst[i], lst[n-1] = lst[n-1], lst[i] 23 | 24 | 25 | if __name__ == '__main__': 26 | n = 3 27 | permute([i for i in range(n)], n) 28 | -------------------------------------------------------------------------------- /math/permute/permute_next_permutation.c: -------------------------------------------------------------------------------- 1 | /* mbinary 2 | ######################################################################### 3 | # File : permute_next_permutation.c 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-11-17 14:31 9 | # Description: support duplicate values. 10 | eg [1,1,5] nextPermutation [1,5,1] 11 | ######################################################################### 12 | */ 13 | #include 14 | 15 | void swap(int*arr,int i,int j) 16 | { 17 | int tmp; 18 | tmp = arr[i]; 19 | arr[i] = arr[j]; 20 | arr[j] = tmp; 21 | } 22 | void reverse(int *arr,int i,int j) 23 | { 24 | while (i1){ 29 | int i; 30 | for(i=n-1;i>0;--i){ 31 | if(arr[i]>arr[i-1])break; 32 | } 33 | i-=1; 34 | if(i>=0){ 35 | for(int j=n-1;j>i;j--){ 36 | if(arr[j]>arr[i]){ 37 | swap(arr,j,i); 38 | break; 39 | } 40 | } 41 | } 42 | reverse(arr,i+1,n-1); 43 | } 44 | } 45 | 46 | void printArr(int *arr,int n) 47 | { 48 | for(int i=0;inode0:v1; 7 | node0:a2->node0:v2; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /parser/PL0-compiler/src/argument_pass.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/parser/PL0-compiler/src/argument_pass.jpg -------------------------------------------------------------------------------- /parser/PL0-compiler/src/data_stack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/parser/PL0-compiler/src/data_stack.jpg -------------------------------------------------------------------------------- /parser/PL0-compiler/src/design.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/parser/PL0-compiler/src/design.pdf -------------------------------------------------------------------------------- /parser/PL0-compiler/src/display.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/parser/PL0-compiler/src/display.pptx -------------------------------------------------------------------------------- /parser/PL0-compiler/src/elseif_ins_stack.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | compound =true 3 | nodesep=.05; 4 | rankdir=LR; 5 | node [shape=record,width=.1,height=.1]; 6 | subgraph cluster_stack{ 7 | label = "instructions stack" 8 | node0 [label = "cond1 | JPC|expr1 | JMP|cond2 | JPC|expr2 | JMP| expr3| ...",height=2.5]; 9 | node0:f1 -> node0:f4; 10 | node0:f3 -> node0:f9; 11 | node0:f5 -> node0:f8; 12 | node0:f7 -> node0:f9; 13 | } 14 | subgraph cluster_elseif{ 15 | label = "program sentences" 16 | node1 [label = "if cond1 |then expr1|elseif cond2 | then expr2|else expr3| ...",height=2.5]; 17 | } 18 | node1 -> node0 [color ="white" ,ltail=cluster_stack, lhead=cluster_elseif]; 19 | } -------------------------------------------------------------------------------- /parser/PL0-compiler/src/elseif_ins_stack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/parser/PL0-compiler/src/elseif_ins_stack.jpg -------------------------------------------------------------------------------- /parser/PL0-compiler/src/return_value.dot: -------------------------------------------------------------------------------- 1 | digraph G{ 2 | nodesep=.05; 3 | rankdir=LR; 4 | node [shape=record,width=.1,height=.1]; 5 | subgraph cluster_1{ 6 | node1[label="{SL|DL|RA}|...|{SL2|DL2|RA2}|...|ret-val"] 7 | "reg: "[shape=ellipse] 8 | } 9 | subgraph cluster_2{ 10 | node2[label="{SL|DL|RA}|...|{SL2|DL2|RA2}|..."] 11 | "reg: ret-val"[shape=ellipse] 12 | } 13 | subgraph cluster_3{ 14 | node3[label="{SL|DL|RA}|..."] 15 | "reg: ret-val "[shape=ellipse] 16 | } 17 | subgraph cluster_4{ 18 | node4[label="{SL|DL|RA}|...|ret-val"] 19 | "reg: ret-val "[shape=ellipse] 20 | } 21 | node1 -> node2 [color="red",label="POP",ltail=cluster_1, lhead=cluster_2]; 22 | node2 -> node3 [color="red",label="RET",ltail=cluster_2, lhead=cluster_3]; 23 | node3 -> node4 [color="red",label="PUSH",ltail=cluster_3, lhead=cluster_4]; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /parser/PL0-compiler/src/return_value.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/parser/PL0-compiler/src/return_value.jpg -------------------------------------------------------------------------------- /parser/PL0-compiler/src/while_ins_stack.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | rankdir=LR; 3 | node [shape=record,width=.1,height=.1]; 4 | subgraph cluster_elseif{ 5 | label = "program sentences" 6 | node1 [label = "while cond |...|break | ...|outer while",height=2.5]; 7 | } 8 | subgraph cluster_stack{ 9 | label = "instructions stack" 10 | node0 [label = "cond | JPC|... | JMP|...| JMP| outer while",height=2.5]; 11 | node0:f1 -> node0:f6; 12 | node0:f3 -> node0:f6; 13 | node0:f5 -> node0:f0; 14 | } 15 | 16 | node1:f2->node0:f3 [color=red] 17 | } -------------------------------------------------------------------------------- /parser/PL0-compiler/src/while_ins_stack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/parser/PL0-compiler/src/while_ins_stack.jpg -------------------------------------------------------------------------------- /parser/PL0-compiler/src/编译原理—pl0实验报告.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/parser/PL0-compiler/src/编译原理—pl0实验报告.doc -------------------------------------------------------------------------------- /parser/PL0-compiler/src/编译原理—pl0实验报告.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/parser/PL0-compiler/src/编译原理—pl0实验报告.pdf -------------------------------------------------------------------------------- /parser/PL0-compiler/src/编译原理和技术实践2017.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/parser/PL0-compiler/src/编译原理和技术实践2017.pdf -------------------------------------------------------------------------------- /parser/PL0-compiler/test/test_token_scanner.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : test_token_scanner.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2019-04-16 09:41 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | import unittest 13 | from token_scanner import gen_token 14 | 15 | class TestTokenScanner(unittest.TestCase): 16 | def Test_gen_token(self): 17 | li = [i for i in gen_token('int a;')] 18 | ans = [Token('NAME','int',1),Token('NAME','a',1),Token('SEMICOLON',';',1)] 19 | self.assertEqual(li,ans) 20 | 21 | if __name__=='__main__': 22 | unittest.main() 23 | -------------------------------------------------------------------------------- /parser/PL0-compiler/test/txt/bug.txt: -------------------------------------------------------------------------------- 1 | func fib(n) 2 | begin 3 | if n=1 || n=2 return 1; 4 | return fib(n-1) +fib(n-2); 5 | end ; 6 | 7 | var n=1; 8 | begin 9 | while n<15 do 10 | begin 11 | print ('The ',n,'th fib item is:',fib(n)); 12 | n :=n+1; 13 | end; 14 | 15 | end 16 | . 17 | -------------------------------------------------------------------------------- /parser/PL0-compiler/test/txt/closure.txt: -------------------------------------------------------------------------------- 1 | var a =1; 2 | func foo(a) 3 | print("[in function foo ] a=%d",a); 4 | func bar(a) 5 | begin 6 | print("[in function bar ] a=%d",a); 7 | foo(4); 8 | end; 9 | begin 10 | print("[in function main] a=%d",a); 11 | foo(2); 12 | bar(3) 13 | end. 14 | -------------------------------------------------------------------------------- /parser/PL0-compiler/test/txt/dowhile.txt: -------------------------------------------------------------------------------- 1 | var n=1; 2 | begin 3 | do 4 | begin 5 | print('%d',n); 6 | n:=n+1; 7 | end 8 | while n<30; 9 | print('zhqnb') 10 | end 11 | . 12 | -------------------------------------------------------------------------------- /parser/PL0-compiler/test/txt/expr.txt: -------------------------------------------------------------------------------- 1 | 2 | // expression 3 | var a=3,b=2,c;. 4 | c:=a+1. 5 | begin c; c+1!=1 ; c+1=5 end. 6 | for(;b>=0;b:=b-1) print('random(100): %d',random(100)) . 7 | begin ++1--1; 1<<2+3%2; 2&1 end. 8 | -1+2*3/%2. 9 | (1+2. 10 | 4!!. 11 | 12 | if 0 then 1 13 | elif 1>2 then 2 14 | elif false then 3 15 | else 4. 16 | 17 | 18 | -------------------------------------------------------------------------------- /parser/PL0-compiler/test/txt/factorial.txt: -------------------------------------------------------------------------------- 1 | func f(n) 2 | begin 3 | if n=1 then return 1; 4 | return n*f(n-1); 5 | end; 6 | 7 | var a; 8 | begin 9 | a:=f(10); 10 | print('factorial 10 is %d',a); 11 | end 12 | . 13 | -------------------------------------------------------------------------------- /parser/PL0-compiler/test/txt/fibonacci.txt: -------------------------------------------------------------------------------- 1 | func fib(n) 2 | begin 3 | if n=1 || n=2 then return 1; 4 | return fib(n-1)+fib(n-2); 5 | end ; 6 | 7 | var n=1; 8 | begin 9 | while n<15 do 10 | begin 11 | print('fib[%d]=%d',n,fib(n)); 12 | n :=n+1; 13 | end; 14 | 15 | end 16 | . 17 | -------------------------------------------------------------------------------- /parser/PL0-compiler/test/txt/gcd.txt: -------------------------------------------------------------------------------- 1 | 2 | // a program 3 | const n=3; 4 | var r,x,n16; 5 | func multiply(a,b) 6 | var c,d; 7 | begin 8 | c:=0; 9 | while 1 do 10 | begin 11 | if b<=0 then break; 12 | if odd b then c:= c+a; 13 | a:=2 * a; b:=b/%2; 14 | end; 15 | return c; 16 | end; 17 | 18 | // comment here 19 | func gcd(f,g) 20 | begin 21 | for(;f!=g;) 22 | begin 23 | if f5 ? 2^4:1 ; 35 | x:=multiply(4,n); 36 | r:=gcd(multiply(4,n),multiply(1,n16)); ; ; 37 | print('r=%d,x=%d,n16=%d ',r,x,n16) 38 | end. 39 | -------------------------------------------------------------------------------- /parser/PL0-compiler/test/txt/switch.txt: -------------------------------------------------------------------------------- 1 | func f(n) 2 | print('squre of %d is %d',n,n*n); 3 | var n=-2; 4 | while n<3 do begin 5 | switch n 6 | case 0:f(n) 7 | case 1,-1:f(n) 8 | case 2,0-2:f(n) ; 9 | n:=n+1; 10 | end. 11 | -------------------------------------------------------------------------------- /parser/PL0-compiler/token_scanner.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ######################################################################### 3 | # File : token_scanner.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-09-17 22:20 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | import re 14 | STR = r'[\'\"](?P.*?)[\'\"]' # not completely correct yet 15 | NAME = r'(?P[a-zA-Z_][a-zA-Z_0-9]*)' 16 | NUM = r'(?P\d*\.\d+|\d+)' # note that don't use \d+|\d*\.\d+ 17 | 18 | ASSIGN = r'(?P\:\=)' 19 | 20 | # ODD = r'(?Podd )' 21 | EQ = r'(?P=)' 22 | NEQ = r'(?P!=)' 23 | GT = r'(?P\>)' 24 | LT = r'(?P\<)' 25 | GE = r'(?P\>\=)' 26 | LE = r'(?P\<\=)' 27 | 28 | BITNOT = r'(?P\~)' 29 | BITOR = r'(?P\|)' 30 | BITAND = r'(?P\&)' 31 | RSHIFT = r'(?P\>\>)' 32 | LSHIFT = r'(?P\<\<)' 33 | 34 | AND = r'(?P\&\&)' 35 | NOT = r'(?P\!)' 36 | OR = r'(?P\|\|)' 37 | 38 | ADD = r'(?P\+)' 39 | SUB=r'(?P\-)' 40 | 41 | MUL = r'(?P\*)' 42 | INTDIV = r'(?P\/\%)' 43 | MOD = r'(?P\%)' 44 | DIV = r'(?P
\/)' 45 | 46 | POW = r'(?P\^)' 47 | FAC=r'(?P\!)' #factorial 48 | 49 | COLON = r'(?P\:)' 50 | COMMA = r'(?P\,)' 51 | SEMICOLON = r'(?P\;)' 52 | PERIOD = r'(?P\.)' 53 | QUESTION = r'(?P\?)' 54 | LEFT=r'(?P\()' 55 | RIGHT=r'(?P\))' 56 | WS = r'(?P\s+)' 57 | 58 | 59 | COMMENT = r'(?P//[^\r\n]*|/\*.*?\*/)' 60 | # note that lt,gt should be after le,ge and rshift, lshift 61 | li = [STR,NUM, AND,OR,BITAND,BITOR,BITNOT,RSHIFT,LSHIFT, 62 | EQ,NEQ,GE,LE,LT,GT,\ 63 | SUB,MOD, ADD, MUL,INTDIV,DIV, POW,FAC,NOT,\ 64 | COMMA,SEMICOLON,PERIOD, QUESTION,WS,LEFT,RIGHT,\ 65 | ASSIGN,COLON,NAME] # COLON behind ASSIGN 66 | master_pat = re.compile('|'.join(li),re.DOTALL) 67 | 68 | class Token: 69 | def __init__(self,tp,value,lineNum=None): 70 | self.type = tp 71 | self.value= value 72 | self.lineNum = lineNum 73 | def __eq__(self,tk): 74 | return self.type==tk.type and self.value==tk.value 75 | def __repr__(self): 76 | s = self.value if self.type!='STR' else '"{}"'.format(repr(self.value)) 77 | return '({},{},{})'.format(self.type,s,self.lineNum) 78 | 79 | def gen_token(text): 80 | li = text .split('\n') 81 | beginComment=False 82 | for i,line in enumerate(li): 83 | s = line.lstrip() 84 | if beginComment: 85 | p = s.find('*/') 86 | if p!=-1: beginComment=False 87 | if p!=-1 and p+2> ') 107 | for i in gen_token(expr): 108 | print(i) 109 | -------------------------------------------------------------------------------- /parser/calculator/calculator.hs: -------------------------------------------------------------------------------- 1 | module Calculator where 2 | 3 | -- calculator, integers, operators: +-*/ 4 | -- "2 / 2 + 3 * 4 - 13" == 0 5 | -- "4 + 3 * 4 / 3 - 6 / 3 * 3 + 8" == 10 6 | -- 7 | -- expr -> factor | expr {+|-} factor 8 | -- factor -> num | factor {*|/} num 9 | 10 | evaluate :: String -> Double 11 | evaluate s = expr.factor.getNum.filter (\x->x/=' ') $s 12 | 13 | 14 | getNum "" = (0,"") 15 | getNum s = let n = length.takeWhile (\x->'0' <=x && x<='9') $s 16 | (num,res) = splitAt n s 17 | x = read num::Double 18 | in (x,res) 19 | 20 | factor (x,s) = if s=="" || s!!0 =='+' || s!!0 =='-' then (x,s) 21 | else let op = head s 22 | (y,s2) = getNum $tail s 23 | z = if op=='*' then x*y else x/y 24 | in factor (z,s2) 25 | 26 | expr (x,s) = if s=="" then x 27 | else let op = head s 28 | (y,s2) = factor.getNum.tail $s 29 | z = if op=='+' then x+y else x-y 30 | in expr (z,s2) 31 | -------------------------------------------------------------------------------- /parser/calculator/genExpr.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : genExpr.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2019-04-16 09:41 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | from random import randint 13 | 14 | 15 | def genOp(li): 16 | return li[randint(0, len(li)-1)] 17 | 18 | 19 | def genNum(n=20): 20 | return randint(1, n) 21 | 22 | 23 | def genFactor(n=3): 24 | n = randint(1, n) 25 | ret = [str(genNum())] 26 | for i in range(n): 27 | ret.append(genOp('*/')) 28 | ret.append(str(genNum())) 29 | return ''.join(ret) 30 | 31 | 32 | def genExpr(n=8): 33 | n = randint(3, n) 34 | ret = [genFactor()] 35 | for i in range(n): 36 | ret.append(genOp('+-')) 37 | ret.append(genFactor()) 38 | return ' '.join(ret) 39 | 40 | 41 | if __name__ == '__main__': 42 | s = genExpr() 43 | print('evaluate "{}" == {}'.format(s, eval(s))) 44 | -------------------------------------------------------------------------------- /parser/declarationParser/README.md: -------------------------------------------------------------------------------- 1 | # C-parser 2 | >A token\_scanner and declaration parser for simplified c using LL(1) 3 | # Rules 4 | * size of int or pointer is 1byte 5 | # Grammar 6 | ```scala 7 | translation_unit 8 | : declaration 9 | | translation_unit declaration 10 | ; 11 | 12 | declaration 13 | : declaration_specifiers init_declarator_list ';' 14 | ; 15 | 16 | declaration_specifiers 17 | : type_specifier 18 | ; 19 | 20 | init_declarator_list 21 | : init_declarator 22 | | init_declarator_list ',' init_declarator 23 | ; 24 | 25 | init_declarator 26 | : declarator 27 | ; 28 | 29 | type_specifier 30 | : VOID 31 | | INT 32 | ; 33 | 34 | declarator 35 | : pointer direct_declarator 36 | | direct_declarator 37 | ; 38 | 39 | direct_declarator 40 | : IDENTIFIER 41 | | '(' declarator ')' 42 | | direct_declarator '[' CONSTANT_INT ']' 43 | | direct_declarator '(' parameter_type_list ')' 44 | | direct_declarator '(' ')' 45 | ; 46 | pointer 47 | : '*' 48 | | '*' pointer 49 | ; 50 | 51 | parameter_type_list 52 | : parameter_list 53 | ; 54 | 55 | parameter_list 56 | : parameter_declaration 57 | | parameter_list ',' parameter_declaration 58 | ; 59 | 60 | parameter_declaration 61 | : declaration_specifiers declarator 62 | ; 63 | ``` 64 | # Examples 65 | ```c 66 | >> int *p,q,j[2]; 67 | p::pointer(int) 68 | q::int 69 | j::array(2,int) 70 | 71 | >> int *p[2][3]; 72 | p::array(2,array(3,pointer(int))) 73 | 74 | >> int (*p[4])[2]; 75 | p::array(4,pointer(array(2,int))) 76 | 77 | >> int (*f(int i,void *j))[2]; 78 | f::function( i::int X j::pointer(void) => pointer(array(2,int))) 79 | 80 | >> int f(void i, void j, int p[2]); 81 | f::function( i::void X j::void X p::array(2,int) => int) 82 | 83 | >> int *f(int i)[2]; 84 | [Error]: Array of Functions is not allowed 85 | 86 | >> int f[2](int k); 87 | [Error]: Array of Function can not be returned from functions 88 | 89 | >> void (*(*paa)[10])(int a); 90 | paa::pointer(array(10,pointer(function( a::int => void)))) 91 | 92 | >> int (*(*(*pg())(int x))[20])(int *y); 93 | pg::function( void => pointer(function( x::int => pointer(array(20,pointer(function( y::pointer(int) => int))))))) 94 | 95 | >> int (*p(int * s,int (*t)(int *m, int n, int (*l())[20]),int k[10]))[10][20]; 96 | p::function( s::pointer(int) X t::pointer(function( m::pointer(int) X n::int X l::function( void => pointer(array(20,int))) => int)) X k::array(10,int) => pointer(array(10,array(20,int)))) 97 | 98 | ``` 99 | -------------------------------------------------------------------------------- /parser/declarationParser/result.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/parser/declarationParser/result.jpg -------------------------------------------------------------------------------- /parser/declarationParser/test.txt: -------------------------------------------------------------------------------- 1 | int *p,q,j[2]; 2 | int *p[2][3]; 3 | int (*p[4])[2]; 4 | int (*f(int i,void *j))[2]; 5 | int f(void i, void j, int p[2]); 6 | //wrong 7 | int *f(int i)[2]; 8 | int f[2](int k); 9 | void (*(*paa)[10])(int a); 10 | int (*(*(*pg())(int x))[20])(int *y); 11 | int (*p(int * s,int (*t)(int *m, int n, int (*l())[20]),int k[10]))[10][20]; 12 | -------------------------------------------------------------------------------- /parser/declarationParser/token_scanner.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ######################################################################### 3 | # File : token_scanner.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-11-01 12:58 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | import re 13 | NAME = r'(?P[a-zA-Z_][a-zA-Z_0-9]*)' 14 | NUM = r'(?P\d*\.\d+|\d+)' # note that don't use \d+|\d*\.\d+ 15 | 16 | POINTER = r'(?P\*)' 17 | COMMA = r'(?P\,)' 18 | SEMICOLON = r'(?P\;)' 19 | 20 | VOID=r'(?Pvoid)' 21 | INT = r'(?Pint)' 22 | LEFT=r'(?P\()' 23 | RIGHT=r'(?P\))' 24 | L2 = r'(?P\[)' 25 | R2 = r'(?P\])' 26 | WS = r'(?P\s+)' 27 | 28 | COMMENT = r'(?P//[^\r\n]*|/\*.*?\*/)' 29 | master_pat = re.compile('|'.join([LEFT,RIGHT,L2,R2,POINTER,COMMA,SEMICOLON,INT,VOID,NUM, WS,NAME]),re.DOTALL) 30 | 31 | class Token: 32 | def __init__(self,tp,val): 33 | self.type = tp 34 | self.value = val 35 | def __repr__(self): 36 | return '({},"{}")'.format(self.type,self.value) 37 | def gen_token(text): 38 | scanner = master_pat.scanner(text) 39 | for m in iter(scanner.match,None): 40 | if m.lastgroup!='WS': 41 | yield Token(m.lastgroup,m.group()) 42 | if __name__ =='__main__': 43 | while 1: 44 | expr = input('>> ') 45 | for i in gen_token(expr): 46 | print(i) 47 | 48 | -------------------------------------------------------------------------------- /parser/leetcode_examples/brace_expansion.py: -------------------------------------------------------------------------------- 1 | import re 2 | from collections import namedtuple 3 | 4 | token = namedtuple('token', ['type', 'value']) 5 | 6 | 7 | left = r'(?P\{)' 8 | right = r'(?P\})' 9 | word = r'(?P[a-z]+)' 10 | comma = r'(?P\,)' 11 | blank = r'(?P\s)' 12 | pt = re.compile('|'.join([left, right, word, comma, blank])) 13 | 14 | 15 | def genToken(s): 16 | scanner = pt.scanner(s) 17 | for i in iter(scanner.match, None): 18 | if i.lastgroup != 'BLANK': 19 | yield token(i.lastgroup, i.group(0)) 20 | 21 | 22 | class parser: 23 | '''gramar 24 | expr -> item | item ',' expr 25 | item -> factor | factor item 26 | factor -> WORD | '{' expr '}' 27 | ''' 28 | 29 | def match(self, tp): 30 | # print(self.p.value) 31 | if tp == self.p.type: 32 | val = self.p.value 33 | try: 34 | self.p = next(self.gen) 35 | except StopIteration: 36 | self.p = None 37 | except Exception as e: 38 | print(e) 39 | return val 40 | else: 41 | raise Exception(f"[Error]: {tp} expected, got {self.p.type}") 42 | 43 | def parse(self, s): 44 | self.gen = genToken(s) 45 | self.p = next(self.gen) 46 | st = self.expr() 47 | return sorted(list(st)) 48 | 49 | def expr(self): 50 | ret = self.item() 51 | while self.p and self.p.type == 'COMMA': 52 | self.match('COMMA') 53 | ret = ret.union(self.item()) 54 | return ret 55 | 56 | def item(self): 57 | ret = self.factor() 58 | while self.p and self.p.type in ['WORD', 'LEFT']: 59 | sufs = self.factor() 60 | new = set() 61 | for pre in ret: 62 | for suf in sufs: 63 | new.add(pre+suf) 64 | ret = new 65 | return ret 66 | 67 | def factor(self): 68 | if self.p.type == 'LEFT': 69 | self.match('LEFT') 70 | ret = self.expr() 71 | self.match('RIGHT') 72 | return ret 73 | return {self.match('WORD')} 74 | 75 | 76 | class Solution: 77 | def braceExpansionII(self, expression): 78 | return parser().parse(expression) 79 | 80 | 81 | if __name__ == '__main__': 82 | sol = Solution() 83 | li = ["{a,b}{c{d,e}}", "{{a,z}, a{b,c}, {ab,z}}", "{a,b}c{d,e}f"] 84 | for i in li: 85 | print('>>>', i) 86 | print(sol.braceExpansionII(i)) 87 | -------------------------------------------------------------------------------- /parser/leetcode_examples/calculator.py: -------------------------------------------------------------------------------- 1 | import re 2 | from collections import namedtuple 3 | left = r'(?P\()' 4 | right = r'(?P\))' 5 | var = r'(?P[a-z]+)' 6 | num = r'(?P\d+)' 7 | add = r'(?P\+)' 8 | sub = r'(?P\-)' 9 | mul = r'(?P\*)' 10 | ws = r'(?P +)' 11 | pt = re.compile('|'.join([left, right, var, ws, num, add, sub, mul])) 12 | 13 | token = namedtuple('token', ['type', 'value']) 14 | 15 | 16 | def genToken(s): 17 | scanner = pt.scanner(s) 18 | for i in iter(scanner.match, None): 19 | if i.lastgroup != 'WS': 20 | yield token(i.lastgroup, i.group(0)) 21 | 22 | 23 | class parser(object): 24 | '''grammar 25 | expr -> expr {'+'|'-'} term | term 26 | term -> term '*' item | item 27 | item -> num | var | '(' expr ')' 28 | ''' 29 | 30 | def __init__(self, s, vars): 31 | self.token = [i for i in genToken(s)] 32 | self.lookahead = 0 33 | self.var = vars 34 | 35 | def parse(self): 36 | dic = self.term() 37 | # terminate symbol 38 | while self.lookahead < len(self.token) and not self.isType('RIGHT'): 39 | assert self.isType('SUB', 'ADD') 40 | sign = 1 if self.match() == '+' else -1 41 | var = self.term() 42 | for i in var: 43 | if i in dic: 44 | dic[i] += var[i]*sign 45 | else: 46 | dic[i] = var[i]*sign 47 | return dic 48 | 49 | def match(self, curType=None): 50 | sym = self.token[self.lookahead] 51 | # print(sym,curType) 52 | if curType is None or sym.type == curType: 53 | self.lookahead += 1 54 | return sym.value 55 | raise Exception('Invalid input string') 56 | 57 | def isType(self, *s): 58 | sym = self.token[self.lookahead] 59 | return any(sym.type == i for i in s) 60 | 61 | def term(self): 62 | li = [] 63 | dic = self.item() 64 | while self.lookahead < len(self.token) and self.isType('MUL'): 65 | self.match() 66 | li.append(self.item()) 67 | for d2 in li: 68 | newDic = {} 69 | for v1 in dic: 70 | for v2 in d2: 71 | s = '' 72 | if v1 == '': 73 | s = v2 74 | elif v2 == '': 75 | s = v1 76 | else: 77 | s = '*'.join(sorted(v1.split('*')+v2.split('*'))) 78 | if s in newDic: 79 | newDic[s] += dic[v1]*d2[v2] 80 | else: 81 | newDic[s] = dic[v1]*d2[v2] 82 | dic = newDic 83 | return dic 84 | 85 | def item(self): 86 | if self.isType('NUM'): 87 | return {'': int(self.match())} 88 | elif self.isType('VAR'): 89 | name = self.match() 90 | if name in self.var: 91 | return {'': self.var[name]} 92 | else: 93 | return {name: 1} 94 | elif self.isType('LEFT'): 95 | self.match() 96 | dic = self.parse() 97 | self.match('RIGHT') 98 | return dic 99 | else: 100 | print(self.token[self.lookahead]) 101 | raise Exception('invalid string') 102 | 103 | 104 | class Solution: 105 | def basicCalculatorIV(self, expression, evalvars, evalints): 106 | """ 107 | :type expression: str 108 | :type evalvars: List[str] 109 | :type evalints: List[int] 110 | :rtype: List[str] 111 | """ 112 | self.var = dict(zip(evalvars, evalints)) 113 | dic = parser(expression, self.var).parse() 114 | n = dic.pop('') if '' in dic else 0 115 | ret = [] 116 | li = sorted(dic, key=lambda s: (-s.count('*'), s)) 117 | for i in li: 118 | if dic[i] != 0: 119 | s = str(dic[i]) 120 | ret.append(s + ('*'+i) if i else s) 121 | if n != 0: 122 | ret.append(str(n)) 123 | return ret 124 | 125 | 126 | if __name__ == '__main__': 127 | sol = Solution() 128 | exprs = [ 129 | "((a - b) * (b - c) + (c - a)) * ((a - b) + (b - c) * (c - a))", "e + 8 - a + 5"] 130 | names = [[], ["e"]] 131 | vars = [[], [1]] 132 | for i, j, k in zip(exprs, names, vars): 133 | print('>>>', i, j, k) 134 | print(sol.basicCalculatorIV(i, j, k)) 135 | -------------------------------------------------------------------------------- /parser/leetcode_examples/lisp_expression.py: -------------------------------------------------------------------------------- 1 | import re 2 | from collections import namedtuple 3 | left = r'(?P\()' 4 | right = r'(?P\))' 5 | word = r'(?P[a-z][a-z0-9]*)' 6 | num = r'(?P(\-)?\d+)' 7 | blank = r'(?P\s+)' 8 | pt = re.compile('|'.join([left, right, word, num, blank])) 9 | 10 | token = namedtuple('token', ['type', 'value']) 11 | 12 | 13 | def genToken(s): 14 | scanner = pt.scanner(s) 15 | for i in iter(scanner.match, None): 16 | if i.lastgroup != 'BLANK': 17 | yield token(i.lastgroup, i.group(0)) 18 | 19 | 20 | class parser(object): 21 | '''grammar: 22 | S-> '(' expr ')' 23 | expr -> [mult|add] item item | let {word item } item 24 | item -> num | word| S 25 | ''' 26 | 27 | def config(self,s): 28 | if s: 29 | self.token = [i for i in genToken(s)] 30 | self.lookahead = 0 31 | self.vars = [] 32 | 33 | def parse(self, s): 34 | self.config(s) 35 | try: 36 | return self.S() 37 | except Exception as e: 38 | return e 39 | 40 | def match(self, curType): 41 | sym = self.token[self.lookahead] 42 | if sym.type == curType: 43 | self.lookahead += 1 44 | return sym.value 45 | self.errorinfo(f'Expected {curType}, got {sym.value}') 46 | 47 | def errorinfo(self, s, k=None): 48 | if k is None: 49 | k = self.lookahead 50 | pre = ' '.join([t.value for t in self.token[:k]]) 51 | suf = ' '.join([t.value for t in self.token[k:]]) 52 | print(pre+' '+suf) 53 | print(' '*(len(pre)+1)+'^'*len(self.token[k].value)) 54 | raise Exception(s) 55 | 56 | def readVar(self, var): 57 | for dic in self.vars[::-1]: 58 | if var in dic: 59 | return dic[var] 60 | self.errorinfo(f"Undefined varible '{var}'", self.lookahead-1) 61 | 62 | def S(self): 63 | self.vars.append({}) 64 | self.match('LEFT') 65 | ret = self.expr() 66 | self.match('RIGHT') 67 | self.vars.pop() 68 | return ret 69 | 70 | def expr(self): 71 | op = self.match('WORD') 72 | if op == 'let': 73 | while self.token[self.lookahead].type != 'RIGHT': 74 | if self.token[self.lookahead].type == 'WORD': 75 | var = self.match('WORD') 76 | if self.token[self.lookahead].type == 'RIGHT': 77 | return self.readVar(var) 78 | else: 79 | self.vars[-1][var] = self.item() 80 | else: 81 | return self.item() 82 | elif op in {'mult', 'add'}: 83 | a = self.item() 84 | b = self.item() 85 | if op == 'mult': 86 | return a*b 87 | elif op == 'add': 88 | return a+b 89 | else: 90 | self.errorinfo('Unknown keyword', self.lookahead-1) 91 | 92 | def item(self): 93 | if self.token[self.lookahead].type == 'WORD': 94 | return self.readVar(self.match('WORD')) 95 | elif self.token[self.lookahead].type == 'NUM': 96 | return int(self.match('NUM')) 97 | else: 98 | return self.S() 99 | 100 | 101 | class Solution(object): 102 | def evaluate(self, expression: str) -> int: 103 | return parser().parse(expression) 104 | 105 | 106 | if __name__ == "__main__": 107 | sol = Solution() 108 | 109 | exprs = ['(add -1 2)', 110 | '(let x -2 y x y)', 111 | '(mult 3 (add 2 3))', 112 | '(let x 2 (mult x 5))', 113 | '(let x 2 (mult x (let x 3 y 4 (add x y))))', 114 | '(let x 2 x 3 x)', 115 | '(let x 2 (add (let x 3 (let x 4 x)) x))', 116 | '(let a1 3 b2 (add a1 1) b2)', 117 | 'add 1 2)', # wrongs 118 | '(asd 1 2)', 119 | '(let a 1 b)', 120 | '(let a 1 b 2)' 121 | ] 122 | for e in exprs: 123 | print('>>>', e) 124 | print(sol.evaluate(e)) 125 | -------------------------------------------------------------------------------- /parser/leetcode_examples/number_of_atoms.py: -------------------------------------------------------------------------------- 1 | import re 2 | from collections import namedtuple 3 | left = r'(?P\()' 4 | right = r'(?P\))' 5 | word = r'(?P[A-Z][a-z]*)' 6 | num = r'(?P\d+)' 7 | pt = re.compile('|'.join([left, right, word, num])) 8 | 9 | token = namedtuple('token', ['type', 'value']) 10 | 11 | 12 | def genToken(s): 13 | scanner = pt.scanner(s) 14 | for i in iter(scanner.match, None): 15 | yield token(i.lastgroup, i.group(0)) 16 | 17 | 18 | class parser: 19 | '''grammar: 20 | S-> item | S item 21 | item -> word | word num | '(' S ')' num 22 | ''' 23 | 24 | def match(self, curType): 25 | sym = self.token[self.lookahead] 26 | if sym.type == curType: 27 | self.lookahead += 1 28 | return sym.value 29 | raise Exception('Invalid input string') 30 | 31 | def parse(self, s): 32 | self.token = [i for i in genToken(s)] 33 | self.lookahead = 0 34 | return self.S() 35 | def S(self): 36 | dic = {} 37 | while self.lookahead < len(self.token) and self.token[self.lookahead].type != 'RIGHT': 38 | cur = self.item() 39 | for i in cur: 40 | if i in dic: 41 | dic[i] += cur[i] 42 | else: 43 | dic[i] = cur[i] 44 | return dic 45 | 46 | def item(self): 47 | if self.token[self.lookahead].type == 'WORD': 48 | ele = self.match('WORD') 49 | n = 1 50 | if self.lookahead < len(self.token) and self.token[self.lookahead].type == 'NUM': 51 | n = int(self.match('NUM')) 52 | return {ele: n} 53 | elif self.token[self.lookahead].type == 'LEFT': 54 | self.match('LEFT') 55 | dic = self.S() 56 | self.match('RIGHT') 57 | n = int(self.match("NUM")) 58 | for i in dic: 59 | dic[i] *= n 60 | return dic 61 | else: 62 | print(self.token[self.lookahead]) 63 | raise Exception('invalid string') 64 | 65 | 66 | class Solution(object): 67 | def countOfAtoms(self, formula): 68 | """ 69 | :type formula: str 70 | :rtype: str 71 | """ 72 | dic = parser().parse(formula) 73 | return ''.join(c+str(dic[c]) if dic[c] != 1 else c for c in sorted(dic.keys())) 74 | 75 | 76 | if __name__ == "__main__": 77 | li = ["K4(ON(SO3)2)2","Mg(OH)2"] 78 | sol = Solution() 79 | for s in li: 80 | print('>>>',s) 81 | print(sol.countOfAtoms(s)) 82 | -------------------------------------------------------------------------------- /search/BFS_knight.hs: -------------------------------------------------------------------------------- 1 | {- mbinary 2 | ######################################################################### 3 | # File : BFS_knight.hs 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-11-11 19:40 9 | # Description: 10 | ######################################################################### 11 | -} 12 | {- 13 | Given two different positions on a chess board, find the least number of moves it would take a knight to get from one to the other. The positions will be passed as two arguments in algebraic notation. For example, knight("a3", "b5") should return 1. 14 | 15 | The knight is not allowed to move off the board. The board is 8x8. 16 | -} 17 | 18 | module ShortestKnightPath.Kata (knight) where 19 | import Data.Char 20 | import Data.List 21 | knight :: String -> String -> Int 22 | knight s1 s2 = let begin = axis s1 23 | end = axis s2 24 | notEnd = all (\tp->tp /=end) 25 | in length . takeWhile notEnd .iterate gen $[begin] 26 | 27 | gen li = nub. flatten $map (filter (\(a,b) ->a>0 && b>0 &&a<9&&b<9 ) . change) li 28 | change (a,b) = [(a-1,b-2),(a-1,b+2),(a+1,b-2),(a+1,b+2),(a+2,b-1),(a+2,b+1),(a-2,b+1),(a-2,b-1)] 29 | 30 | axis s = (ord (s!!0) -96, digitToInt (s!!1)::Int) 31 | 32 | flatten [] = [] 33 | flatten (x:xs) = x ++ flatten xs 34 | 35 | -------------------------------------------------------------------------------- /search/binary_search.hs: -------------------------------------------------------------------------------- 1 | search i li= binary 0 $length li -1 2 | where binary a b= let mid = div (a+b) 2 3 | p = li!!mid 4 | in if a>=b then a 5 | else if p==i then mid 6 | else if p>i then binary a $mid-1 7 | else binary (mid+1) b 8 | -------------------------------------------------------------------------------- /search/bloomFilter.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : bloomFilter.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-10-17 11:19 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | from bitarray import bitarray 13 | 14 | import mmh3 15 | 16 | 17 | class bloomFilter(set): 18 | def __init__(self, size, hash_count): 19 | super(bloomFilter, self).__init__() 20 | self.bits = bitarray(size) 21 | self.bits.setall(0) 22 | self.size = size 23 | self.hash_count = hash_count 24 | 25 | def __len__(self): 26 | return self.size 27 | 28 | def __iter__(self): 29 | return iter(self.bits) 30 | 31 | def add(self, item): 32 | for i in range(self.hash_count): 33 | idx = mmh3.hash(item, i) % self.size 34 | self.bits[idx] = 1 35 | return self 36 | 37 | def __contains__(self, item): 38 | idxs = [mmh3.hash(item, i) % self.size for i in range(self.hash_count)] 39 | return all([self.bits[i] == 1 for i in idxs]) 40 | -------------------------------------------------------------------------------- /search/schedule.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : schedule.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-11-30 12:00 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | ''' 13 | 回溯全空间搜索, 剪枝优化 14 | 15 | 16 | 设有n个任务由k个可并行工作的机器来完成,完成任务i需要时间为 。试设计一个算法找出完成这n个任务的最佳调度,使完成全部任务的时间最早。 17 | ''' 18 | 19 | 20 | 21 | 22 | from time import time 23 | from functools import total_ordering 24 | @total_ordering 25 | class record: 26 | def __init__(self, nums=None): 27 | if nums is None: 28 | nums = [] 29 | self.nums = nums 30 | self.sum = sum(nums) 31 | 32 | def append(self, x): 33 | self.nums.append(x) 34 | self.sum += x 35 | 36 | def pop(self): 37 | x = self.nums.pop() 38 | self.sum -= x 39 | return x 40 | 41 | def __repr__(self): 42 | return repr(self.nums) 43 | 44 | def __lt__(self, r): 45 | return self.sum < r.sum 46 | 47 | def __eq__(self, r): 48 | return self.sum == r.sum 49 | 50 | def tolist(self): 51 | return self.nums.copy() 52 | 53 | def __hash__(self): 54 | return self.sum 55 | 56 | 57 | def schedule(works, k): 58 | def backtrackSearch(i, lsts): 59 | nonlocal best, rst 60 | if i == n: 61 | cost = max(r.sum for r in lsts) 62 | if best > cost: 63 | best = cost 64 | rst = [st.tolist() for st in lsts] 65 | else: 66 | for cur in set(lsts): 67 | if best > cur.sum+works[i]: 68 | cur.append(works[i]) 69 | backtrackSearch(i+1, lsts) 70 | cur.pop() 71 | 72 | def findInitial(i, lst): 73 | nonlocal best 74 | if i == n: 75 | cost = max(lst) 76 | if best > cost: 77 | best = cost 78 | else: 79 | mn = lst[0] 80 | idx = 0 81 | visited = set() 82 | for j, cur in enumerate(lst): 83 | if cur not in visited: 84 | visited.add(cur) 85 | if mn > cur: 86 | mn = cur 87 | idx = j 88 | lst[idx] += works[i] 89 | findInitial(i+1, lst) 90 | lst[idx] -= works[i] 91 | 92 | n = len(works) 93 | print() 94 | print('machine Num:', n) 95 | print('works :', works) 96 | rst = None 97 | works.sort(reverse=True) # key step 98 | best = sum(works[:n-k+1]) 99 | t = time() 100 | findInitial(0, [0]*k) # key step 101 | t1 = time()-t 102 | print('init solution: {} cost time {:.6f}s'.format(best, t1)) 103 | t = time() 104 | backtrackSearch(0, [record() for i in range(k)]) 105 | t2 = time()-t 106 | print('final solution: {} cost time {:.6f}s'.format(best, t2)) 107 | print('schedule plan:', rst) 108 | return best, rst 109 | 110 | 111 | if __name__ == '__main__': 112 | from random import randint 113 | schedule([47, 20, 28, 44, 21, 45, 30, 39, 28, 33], 3) 114 | schedule([98, 84, 50, 23, 32, 99, 22, 76, 72, 61, 81, 39, 76, 54, 37], 5) 115 | schedule([39, 39, 23, 45, 100, 69, 21, 81, 39, 55, 116 | 20, 86, 34, 53, 58, 99, 36, 45, 46], 8) 117 | 118 | ''' 119 | machine Num: 19 120 | works : [39, 39, 23, 45, 100, 69, 21, 81, 39, 55, 20, 86, 34, 53, 58, 99, 36, 45, 46] 121 | 122 | works 经过逆序排序 123 | init solution: 135 cost time 0.000196s 124 | final solution: 126 cost time 0.022922s 125 | schedule plan: [[100, 21], [99, 23], [86, 39], [81, 45], [69, 53], [58, 45, 20], [55, 36, 34], [46, 39, 39]] 126 | 127 | works 没有经过排序 128 | init solution: 168 cost time 0.000179s 129 | final solution: 126 cost time 10.646307s 130 | schedule plan: [[39, 86], [39, 34, 53], [23, 99], [45, 39, 36], [100, 20], [69, 55], [21, 58, 46], [81, 45]] 131 | ''' 132 | -------------------------------------------------------------------------------- /search/work_dispatch.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : work_dispatch.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2019-04-16 09:41 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | ''' 13 | 设有n件工作要分配给n个人去完成,将工作i分配给第j个人所需费用为c_ij 。试设计一个算法,为每个人分配1件不同的工作,并使总费用达到最小。 14 | ''' 15 | 16 | 17 | 18 | 19 | import random 20 | def dispatch(mat): 21 | '''mat: matrix of c_ij''' 22 | def _util(i, arrange, cost): 23 | ''' for i-th work''' 24 | nonlocal total, used, rst 25 | if i == n: 26 | total = cost 27 | rst = arrange.copy() # copy is needed 28 | else: 29 | for j in range(n): 30 | if not used[j] and(total is None or cost+mat[i][j] < total): 31 | used[j] = True 32 | arrange[i] = j 33 | _util(i+1, arrange, cost+mat[i][j]) 34 | used[j] = False 35 | total = None 36 | rst = None 37 | n = len(mat) 38 | used = [False for i in range(n)] 39 | _util(0, [-1]*n, 0) 40 | return total, rst 41 | 42 | 43 | if __name__ == '__main__': 44 | n = 10 45 | mat = [[random.randint(1, 100) for i in range(n)] for i in range(n)] 46 | print('work matrix: c_ij: work_i and person_j') 47 | for i in range(n): 48 | print(mat[i]) 49 | print('result: ', end='') 50 | print(dispatch(mat)) 51 | -------------------------------------------------------------------------------- /sort/__pycache__/quickSort.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/sort/__pycache__/quickSort.cpython-35.pyc -------------------------------------------------------------------------------- /sort/__pycache__/select.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/sort/__pycache__/select.cpython-37.pyc -------------------------------------------------------------------------------- /sort/binaryTree.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : sort.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-07-05 17:18 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | from functools import total_ordering 14 | 15 | 16 | @total_ordering 17 | class node: 18 | def __init__(self, val, left=None, right=None): 19 | self.val = val 20 | self.frequency = 1 21 | self.left = left 22 | self.right = right 23 | 24 | def __lt__(self, x): 25 | return self.val < x.val 26 | 27 | def __eq__(self, x): 28 | return self.val == x.val 29 | 30 | def inc(self): 31 | self.val += 1 32 | 33 | def dec(self): 34 | self.val -= 1 35 | 36 | def incFreq(self): 37 | self.frequency += 1 38 | 39 | def decFreq(self): 40 | self.frequency -= 1 41 | 42 | 43 | class binaryTree: 44 | def __init__(self, reverse=True): 45 | self.reverse = reverse 46 | self.data = None 47 | 48 | def cmp(self, n1, n2): 49 | ret = 0 50 | if n1 < n2: 51 | ret = -1 52 | if n1 > n2: 53 | ret = 1 54 | return ret * -1 if self.reverse else ret 55 | 56 | def addNode(self, nd): 57 | def _add(prt, chd): 58 | if self.cmp(prt, chd) == 0: 59 | prt.incFreq() 60 | return 61 | if self.cmp(prt, chd) < 0: 62 | 63 | if not isinstance(nd, node): 64 | nd = node(nd) 65 | if not self.root: 66 | self.root = node(val) 67 | else: 68 | if self.root == val: 69 | self.root.incfreq() 70 | else: 71 | cur = self.root 72 | 73 | def build(self, lst): 74 | dic = {} 75 | for i in lst: 76 | if i in dic: 77 | dic[i].incFreq() 78 | else: 79 | dic[i] = node(i) 80 | self.data = list(dic.values()) 81 | -------------------------------------------------------------------------------- /sort/heapSort.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : heapSort.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-07-05 16:24 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | from functools import partial 14 | 15 | 16 | class heap: 17 | def __init__(self, lst, reverse=False): 18 | self.data = heapify(lst, reverse) 19 | self.cmp = partial(lambda i, j, r: cmp( 20 | self.data[i], self.data[j], r), r=reverse) 21 | 22 | def getTop(self): 23 | return self.data[0] 24 | 25 | def __getitem__(self, idx): 26 | return self.data[idx] 27 | 28 | def __bool__(self): 29 | return self.data != [] 30 | 31 | def popTop(self): 32 | ret = self.data[0] 33 | n = len(self.data) 34 | cur = 1 35 | while cur * 2 <= n: 36 | chd = cur-1 37 | r_idx = cur*2 38 | l_idx = r_idx-1 39 | if r_idx == n: 40 | self.data[chd] = self.data[l_idx] 41 | break 42 | j = l_idx if self.cmp(l_idx, r_idx) < 0 else r_idx 43 | self.data[chd] = self.data[j] 44 | cur = j+1 45 | self.data[cur-1] = self.data[-1] 46 | self.data.pop() 47 | return ret 48 | 49 | def addNode(self, val): 50 | self.data.append(val) 51 | self.data = one_heapify(len(self.data)-1) 52 | 53 | 54 | def cmp(n1, n2, reverse=False): 55 | fac = -1 if reverse else 1 56 | if n1 < n2: 57 | return -fac 58 | elif n1 > n2: 59 | return fac 60 | return 0 61 | 62 | 63 | def heapify(lst, reverse=False): 64 | for i in range(len(lst)): 65 | lst = one_heapify(lst, i, reverse) 66 | return lst 67 | 68 | 69 | def one_heapify(lst, cur, reverse=False): 70 | cur += 1 71 | while cur > 1: 72 | chd = cur-1 73 | prt = cur//2-1 74 | if cmp(lst[prt], lst[chd], reverse) < 0: 75 | break 76 | lst[prt], lst[chd] = lst[chd], lst[prt] 77 | cur = prt+1 78 | return lst 79 | 80 | 81 | def heapSort(lst, reverse=False): 82 | lst = lst.copy() 83 | hp = heap(lst, reverse) 84 | ret = [] 85 | while hp: 86 | ret.append(hp.popTop()) 87 | return ret 88 | 89 | 90 | if __name__ == '__main__': 91 | from random import randint 92 | n = randint(10, 20) 93 | lst = [randint(0, 100) for i in range(n)] 94 | print('random : ', lst) 95 | print('small-heap: ', heapify(lst)) 96 | print('big-heap : ', heapify(lst, True)) 97 | print('ascend : ', heapSort(lst)) 98 | print('descend : ', heapSort(lst, True)) 99 | -------------------------------------------------------------------------------- /sort/quickSort.c: -------------------------------------------------------------------------------- 1 | /* mbinary 2 | ######################################################################### 3 | # File : quickSort.c 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2019-04-16 09:41 9 | # Description: 10 | ######################################################################### 11 | */ 12 | int partition(int *arr, int i, int j) 13 | { 14 | int pivot = arr[j], p = i, q = j; 15 | 16 | while (p < q) { 17 | while (p < q && arr[p] <= pivot)++p; 18 | 19 | if (p < q)arr[q--] = arr[p]; 20 | 21 | while (p < q && arr[q] > pivot)--q; 22 | 23 | if (p < q)arr[p++] = arr[q]; 24 | } 25 | 26 | arr[p] = pivot; 27 | return p; 28 | } 29 | void quickSort(int *arr, int i, int j) 30 | { 31 | if (i < j) { 32 | int p = partition(arr, i, j); 33 | quickSort(arr, i, p - 1); 34 | quickSort(arr, p + 1, j); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /sort/quickSort.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : quickSort.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-07-06 10:31 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | 14 | from time import time 15 | 16 | 17 | def quickSort(lst): 18 | '''A optimized version of Hoare partition''' 19 | 20 | def partition(a, b): 21 | pivot = lst[a] 22 | while a != b: 23 | while a < b and lst[b] > pivot: 24 | b -= 1 25 | if a < b: 26 | lst[a] = lst[b] 27 | a += 1 28 | while a < b and lst[a] < pivot: 29 | a += 1 30 | if a < b: 31 | lst[b] = lst[a] 32 | b -= 1 33 | lst[a] = pivot 34 | return a 35 | 36 | def _sort(a, b): 37 | if a >= b: 38 | return 39 | mid = (a + b) // 2 40 | # 三数取中值置于第一个作为 pivot 41 | if (lst[a] < lst[mid]) ^ (lst[b] < lst[mid]): 42 | lst[a], lst[mid] = lst[mid], lst[a] # lst[mid] 为中值 43 | if (lst[a] < lst[b]) ^ (lst[b] > lst[mid]): 44 | lst[a], lst[b] = lst[b], lst[a] # lst[b] 为中值 45 | i = partition(a, b) 46 | _sort(a, i - 1) 47 | _sort(i + 1, b) 48 | 49 | _sort(0, len(lst) - 1) 50 | return lst 51 | 52 | 53 | def quickSort2(lst): 54 | '''A version of partition from , a little bit slow''' 55 | 56 | def partition(a, b): 57 | pivot = lst[b] 58 | j = a - 1 59 | for i in range(a, b): 60 | if lst[i] <= pivot: 61 | j += 1 62 | if i != j: 63 | lst[i], lst[j] = lst[j], lst[i] 64 | lst[j + 1], lst[b] = lst[b], lst[j + 1] 65 | return j + 1 66 | 67 | def _sort(a, b): 68 | if a >= b: 69 | return 70 | mid = (a + b) // 2 71 | # 三数取中值置于第一个作为 pivot 72 | if (lst[a] < lst[mid]) ^ (lst[b] < lst[mid]): 73 | lst[b], lst[mid] = lst[mid], lst[b] # lst[mid] 为中值 74 | if (lst[a] > lst[b]) ^ (lst[a] > lst[mid]): 75 | lst[a], lst[b] = lst[b], lst[a] # lst[b] 为中值 76 | i = partition(a, b) 77 | _sort(a, i - 1) 78 | _sort(i + 1, b) 79 | 80 | _sort(0, len(lst) - 1) 81 | return lst 82 | 83 | 84 | def quickSort3(lst): 85 | '''A rear recursive optimization version''' 86 | 87 | def partition(a, b): 88 | pivot = lst[b] 89 | j = a - 1 90 | for i in range(a, b): 91 | if lst[i] <= pivot: 92 | j += 1 93 | if i != j: 94 | lst[i], lst[j] = lst[j], lst[i] 95 | lst[j + 1], lst[b] = lst[b], lst[j + 1] 96 | return j + 1 97 | 98 | def _sort(a, b): 99 | while a < b: 100 | mid = (a + b) // 2 101 | # 三数取中值置于第一个作为 pivot 102 | if (lst[a] < lst[mid]) ^ (lst[b] < lst[mid]): 103 | lst[b], lst[mid] = lst[mid], lst[b] # lst[mid] 为中值 104 | if (lst[a] > lst[b]) ^ (lst[a] > lst[mid]): 105 | lst[a], lst[b] = lst[b], lst[a] # lst[b] 为中值 106 | i = partition(a, b) 107 | _sort(a, i - 1) 108 | a = i + 1 109 | 110 | _sort(0, len(lst) - 1) 111 | return lst 112 | 113 | 114 | def timer(func, lst, n=100): 115 | t = time() 116 | for i in range(n): 117 | func(lst) 118 | t = time() - t 119 | print('{}: {}s'.format(func.__name__, t)) 120 | return t 121 | 122 | 123 | if __name__ == '__main__': 124 | from random import randint 125 | print('5000 items, repeat 100 times for each') 126 | lst = [randint(0, 100) for i in range(5000)] 127 | timer(quickSort, lst.copy()) 128 | timer(quickSort2, lst.copy()) 129 | timer(quickSort3, lst.copy()) 130 | 131 | lst = [randint(0, 100) for i in range(15)] 132 | print(lst) 133 | print(quickSort(lst.copy())) 134 | print(quickSort2(lst.copy())) 135 | print(quickSort3(lst.copy())) 136 | -------------------------------------------------------------------------------- /sort/radixSort.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : radixSort.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-07-06 15:52 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | from random import randint 14 | from quickSort import quickSort 15 | from time import time 16 | 17 | 18 | def radixSort(lst, radix=10): 19 | ls = [[] for i in range(radix)] 20 | mx = max(lst) 21 | weight = 1 22 | while mx >= weight: 23 | for i in lst: 24 | ls[(i // weight) % radix].append(i) 25 | weight *= radix 26 | lst = sum(ls, []) 27 | ls = [[] for i in range(radix)] 28 | return lst 29 | 30 | 31 | def countSort(lst, mn, mx): 32 | mark = [0]*(mx-mn+1) 33 | for i in lst: 34 | mark[i-mn] += 1 35 | ret = [] 36 | for n, i in enumerate(mark): 37 | ret += [n+mn]*i 38 | return ret 39 | 40 | 41 | def timer(funcs, span, num=1000000): 42 | lst = [randint(0, span) for i in range(num)] 43 | print('range({}), {} items'.format(span, num)) 44 | for func in funcs: 45 | data = lst.copy() 46 | t = time() 47 | func(data) 48 | t = time()-t 49 | print('{}: {}s'.format(func.__name__, t)) 50 | 51 | 52 | if __name__ == '__main__': 53 | timer([quickSort, radixSort, sorted], 1000000000000, 1000) 54 | timer([quickSort, radixSort, sorted], 10000, 100000) 55 | lst = [randint(0, 100) for i in range(1000)] 56 | print(countSort(lst, 0, 100) == sorted(lst)) 57 | -------------------------------------------------------------------------------- /sort/select.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : select.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-07-06 17:13 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | from random import randint 14 | 15 | 16 | def select(lst, i): 17 | lst = lst.copy() 18 | 19 | def partition(a, b): 20 | pivot = lst[a] 21 | while a < b: 22 | while a < b and lst[b] > pivot: 23 | b -= 1 24 | if a < b: 25 | lst[a] = lst[b] 26 | a += 1 27 | while a < b and lst[a] < pivot: 28 | a += 1 29 | if a < b: 30 | lst[b] = lst[a] 31 | b -= 1 32 | lst[a] = pivot 33 | return a 34 | 35 | def _select(a, b): 36 | if a >= b: 37 | return lst[a] 38 | # randomized select 39 | n = randint(a, b) 40 | lst[a], lst[n] = lst[n], lst[a] 41 | pos = partition(a, b) 42 | if pos > i: 43 | return _select(a, pos-1) 44 | elif pos < i: 45 | return _select(pos+1, b) 46 | else: 47 | return lst[pos] 48 | return _select(0, len(lst)-1) 49 | 50 | 51 | if __name__ == '__main__': 52 | lst = [randint(0, 1000) for i in range(100)] 53 | st = sorted(lst) 54 | for i in range(10): 55 | n = randint(0, 99) 56 | print('select {}th: \nexpect: {}\ngot: {}'.format( 57 | n, st[n], select(lst, n))) 58 | -------------------------------------------------------------------------------- /sort/shellSort.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : shellSort.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-07-06 16:30 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | 14 | def shellSort(s, gaps=None): 15 | if gaps is None: 16 | gaps = [127, 63, 31, 15, 7, 3, 1] 17 | n = len(s) 18 | for gap in gaps: 19 | for j in range(gap, n): 20 | cur = j 21 | num = s[j] 22 | while cur >= gap and num < s[cur-gap]: 23 | s[cur] = s[cur-gap] 24 | cur -= gap 25 | s[cur] = num 26 | return s 27 | 28 | 29 | if __name__ == '__main__': 30 | from random import randint 31 | import sys 32 | n = 20 33 | if len(sys.argv) > 1: 34 | n = int(sys.argv[1]) 35 | nums = [randint(1, 100) for i in range(n)] 36 | print(nums) 37 | print(shellSort(nums)) 38 | -------------------------------------------------------------------------------- /string/KMP.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ######################################################################### 4 | # File : KMP.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2018-12-11 14:02 10 | # Description: 11 | ######################################################################### 12 | ''' 13 | 14 | 15 | def getPrefixFunc(s): 16 | '''return the list of prefix function of s''' 17 | length = 0 18 | i = 1 19 | n = len(s) 20 | ret = [0] 21 | while i < n: 22 | if s[i] == s[length]: 23 | length += 1 24 | ret.append(length) 25 | i += 1 26 | else: 27 | if length == 0: 28 | ret.append(0) 29 | i += 1 30 | else: 31 | length = ret[length-1] 32 | return ret 33 | 34 | 35 | def findAll(s, p): 36 | pre = getPrefixFunc(p) 37 | i = j = 0 38 | n, m = len(s), len(p) 39 | ret = [] 40 | while i < n: 41 | if s[i] == p[j]: 42 | i += 1 43 | j += 1 44 | if j == m: 45 | ret.append(i-j) 46 | j = pre[j-1] 47 | else: 48 | if j == 0: 49 | i += 1 50 | else: 51 | j = pre[j-1] 52 | return ret 53 | 54 | 55 | def randStr(n=3): 56 | return [randint(ord('a'), ord('z')) for i in range(n)] 57 | 58 | 59 | if __name__ == '__main__': 60 | from random import randint 61 | s = randStr(50) 62 | p = randStr(1) 63 | print(s) 64 | print(p) 65 | print(findAll(s, p)) 66 | -------------------------------------------------------------------------------- /string/manacher.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : manacher.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-07-06 15:56 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | 14 | class Solution: 15 | def longestPalindrome(self, s): 16 | """ 17 | :type s: str 18 | :rtype: str 19 | """ 20 | n = len(s) 21 | s2 = '$#'+'#'.join(s)+'#@' 22 | ct = [0]*(2*n+4) 23 | mid = 1 24 | for cur in range(1, 2*n+2): 25 | if cur < mid+ct[mid]: 26 | ct[cur] = min(ct[2*mid-cur], mid+ct[mid]-cur) 27 | else: 28 | ct[cur] = 1 29 | while s2[cur-ct[cur]] == s2[cur+ct[cur]]: 30 | ct[cur] += 1 31 | if cur+ct[cur] > mid+ct[mid]: 32 | mid = cur 33 | mx = max(ct) 34 | idxs = [i for i, j in enumerate(ct) if j == mx] 35 | p = idxs[0] 36 | for i in idxs: 37 | if s2[i] == '#': 38 | p = i 39 | rst = s2[p-mx+1:p+mx].replace('#', '') 40 | return rst 41 | -------------------------------------------------------------------------------- /string/markov.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : markov.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-07-06 15:57 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | from random import randint 14 | import re 15 | 16 | 17 | class markov: 18 | def __init__(self, txt): 19 | self.words = self.clean(txt) 20 | self.dic = self.getDic(self.words) 21 | 22 | def clean(self, text): 23 | text = text.replace("\n", " ") 24 | text = text.replace("\"", "") 25 | 26 | # 保证每个标点符号都和前面的单词在一起 27 | # 这样不会被剔除,保留在马尔可夫链中 28 | punctuation = [',', '.', ';', ':'] 29 | for symbol in punctuation: 30 | text = text.replace(symbol, symbol+" ") 31 | 32 | return re.split(' +', text) 33 | 34 | def getDic(self, words): 35 | dic = {} 36 | end = len(words) 37 | for i in range(1, end): 38 | if words[i-1] not in dic: 39 | dic[words[i-1]] = {words[i]: 1} 40 | elif words[i] not in dic[words[i-1]]: 41 | dic[words[i-1]][words[i]] = 1 42 | else: 43 | dic[words[i-1]][words[i]] += 1 44 | return dic 45 | 46 | def getSum(self, dic): 47 | if '%size' not in dic: 48 | dic['%size'] = sum(list(dic.values())) 49 | return dic['%size'] 50 | 51 | def nextWord(self, word): 52 | k = randint(1, self.getSum(self.dic[word])) 53 | for i, j in self.dic[word].items(): 54 | k -= j 55 | if k <= 0: 56 | return i 57 | 58 | def genSentence(self, begin='I', length=30): 59 | li = [begin] 60 | nextWord = begin 61 | for i in range(1, length): 62 | nextWord = self.nextWord(nextWord) 63 | li.append(nextWord) 64 | return ' '.join(li) 65 | -------------------------------------------------------------------------------- /string/min-window-substring.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : min-window-substring.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2019-05-26 21:39 10 | # Description: 11 | from leetcode-cn #76: https://leetcode-cn.com/problems/minimum-window-substring/ 12 | 13 | 给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。 14 | 输入: S = "ADOBECODEBANC", T = "ABC" 15 | 输出: "BANC" 16 | 说明: 17 | 如果 S 中不存这样的子串,则返回空字符串 ""。 18 | 如果 S 中存在这样的子串,我们保证它是唯一的答案。 19 | 20 | since you have to find the minimum window in S which has all the characters from T, you need to expand and contract the window using the two pointers and keep checking the window for all the characters. This approach is also called Sliding Window Approach. 21 | 22 | L ------------------------ R , Suppose this is the window that contains all characters of T 23 | L----------------- R , this is the contracted window. We found a smaller window that still contains all the characters in T 24 | 25 | When the window is no longer valid, start expanding again using the right pointer. 26 | ####################################################################### 27 | ''' 28 | 29 | from collections import defaultdict 30 | 31 | 32 | class Solution: 33 | def minWindow(self, s: str, t: str) -> str: 34 | def expand(j, lacked, dic): 35 | while j < n and lacked: 36 | if s[j] in lacked: 37 | lacked[s[j]] -= 1 38 | if lacked[s[j]] == 0: 39 | del lacked[s[j]] 40 | dic[s[j]] += 1 41 | j += 1 42 | return j 43 | 44 | def contract(left, right): 45 | for i in range(left, right): 46 | dic[s[i]] -= 1 47 | if dic[s[i]] == 0: 48 | del dic[s[i]] 49 | if s[i] in chars and (s[i] not in dic or dic[s[i]] < chars[s[i]]): 50 | return i+1, {s[i]: 1} 51 | n, i, j = len(s), 0, 0 52 | ans = '' 53 | dic, lacked = defaultdict(int), defaultdict(int) 54 | for c in t: 55 | lacked[c] += 1 56 | chars = lacked.copy() 57 | while j < n and lacked: 58 | j = expand(j, lacked, dic) 59 | if not lacked: 60 | i, lacked = contract(i, j) 61 | if ans == '' or len(ans) > j-i+1: 62 | ans = s[i-1:j] 63 | return ans 64 | -------------------------------------------------------------------------------- /string/rabin_karp.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ######################################################################### 4 | # File : rabin_karp.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2018-12-11 00:01 10 | # Description: rabin-karp algorithm 11 | ######################################################################### 12 | ''' 13 | 14 | 15 | def isPrime(x): 16 | for i in range(2, int(x**0.5)+1): 17 | if x % i == 0: 18 | return False 19 | return True 20 | 21 | 22 | def getPrime(x): 23 | '''return a prime which is bigger than x''' 24 | for i in range(x, 2*x): 25 | if isPrime(i): 26 | return i 27 | 28 | 29 | def findAll(s, p): 30 | '''s: string p: pattern''' 31 | dic = {} 32 | n, m = len(s), len(p) 33 | d = 0 # radix 34 | for c in s: 35 | if c not in dic: 36 | dic[c] = d 37 | d += 1 38 | sm = 0 39 | for c in p: 40 | if c not in dic: 41 | return [] 42 | sm = sm*d+dic[c] 43 | 44 | ret = [] 45 | cur = 0 46 | for i in range(m): 47 | cur = cur*d + dic[s[i]] 48 | if cur == sm: 49 | ret.append(0) 50 | tmp = n-m 51 | q = getPrime(m) 52 | cur = cur % q 53 | sm = sm % q 54 | exp = d**(m-1) % q 55 | for i in range(m, n): 56 | cur = ((cur-dic[s[i-m]]*exp)*d+dic[s[i]]) % q 57 | if cur == sm and p == s[i-m+1:i+1]: 58 | ret.append(i-m+1) 59 | return ret 60 | 61 | 62 | def randStr(n=3): 63 | return [randint(ord('a'), ord('z')) for i in range(n)] 64 | 65 | 66 | if __name__ == '__main__': 67 | from random import randint 68 | s = randStr(50) 69 | p = randStr(1) 70 | print(s) 71 | print(p) 72 | print(findAll(s, p)) 73 | -------------------------------------------------------------------------------- /string/rotate.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : rotate.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-05-19 21:54 9 | # Description: three methods of rotating a list 10 | 11 | 1. 利用 ba=(br)^T(ar)^T=(arbr)^T,通过三次反转字符串: 即首先对序列前部分逆序,再对序列后部分逆序,再对整个序列全部逆序 12 | 13 | 2. 分组交换(尽可能使数组的前面连续几个数为所要结果):a长度大于b,将 ab 分成 a0a1b,交换 a0 和 b,得 ba1a0,只需再交换 a1和 a0。若 a 长度小于 b,将 ab 分成 ab0b1,交换 a 和 b0,得 b0ab1,只需再交换 a 和b0。通过不断将数组划分,和交换,直到不能再划分为止。分组过程与求最大公约数很相似。 14 | 15 | 3.所有序号为 (j+i*m) % n (j 表示每个循环链起始位置,i 为计数变量,m 表示左旋转位数,n 表示字符串长度),会构成一个循环链(共有 gcd(n,m)个,gcd 为 n、m 的最大公约数),每个循环链上的元素只要移动一个位置即可,最后整个过程总共交换了 n 次(每一次循环链,是交换 n/gcd(n,m)次,总共 gcd(n,m)个循环链。所以,总共交换 n 次)。 16 | 17 | ######################################################################### 18 | ''' 19 | 20 | 21 | def rotate(s, k, right=False): 22 | def reverse(a, b): 23 | while a < b: 24 | s[a], s[b] = s[b], s[a] 25 | a += 1 26 | b -= 1 27 | n = len(s) 28 | k = k % n if not right else n-k % n 29 | reverse(0, k-1) 30 | reverse(k, n-1) 31 | reverse(0, n-1) 32 | return s 33 | 34 | 35 | def rotate2(s, k, right=False): 36 | def swap(a, b, c): 37 | for i in range(c): 38 | s[a+i], s[b+i] = s[b+i], s[a+i] 39 | 40 | def _rot(pl, pr): 41 | ''' swap s[pl,pr) , s[pr:]''' 42 | if pr == n: 43 | return 44 | if pr-pl <= n-pr: 45 | swap(pl, pr, pr-pl) 46 | _rot(pr, 2*pr-pl) 47 | else: 48 | swap(pl, pr, n-pr) 49 | _rot(n-pr+pl, pr) 50 | n = len(s) 51 | k = k % n if not right else n-k % n 52 | _rot(0, k) 53 | return s 54 | 55 | 56 | def rotate3(s, k, right=False): 57 | def gcd(a, b): 58 | if b == 0: 59 | return a 60 | return gcd(b, a % b) 61 | 62 | n = len(s) 63 | k = k % n if not right else n-k % n 64 | r = gcd(n, k) 65 | for i in range(r): 66 | tmp = s[i] 67 | j = (i+k) % n 68 | while j != i: 69 | s[j-k] = s[j] 70 | j = (j+k) % n 71 | s[(j-k+n) % n] = tmp 72 | return s 73 | 74 | 75 | def test(): 76 | def f(func, *args, right=False): 77 | print(' '.join(['testing:', func.__name__, 78 | str(args), 'right=', str(right)])) 79 | rst = func(*args, right=right) 80 | print('result', rst) 81 | print() 82 | return f 83 | 84 | 85 | if __name__ == '__main__': 86 | s = [i for i in range(10)] 87 | tester = test() 88 | tester(rotate, s, 4, right=True) 89 | tester(rotate, s, 4) 90 | tester(rotate2, s, 2, right=True) 91 | tester(rotate2, s, 2) 92 | tester(rotate3, s, 132, right=True) 93 | tester(rotate3, s, 132) 94 | 95 | 96 | ''' 97 | testing: rotate ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 4) right= True 98 | result [6, 7, 8, 9, 0, 1, 2, 3, 4, 5] 99 | 100 | testing: rotate ([6, 7, 8, 9, 0, 1, 2, 3, 4, 5], 4) right= False 101 | result [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 102 | 103 | testing: rotate2 ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 2) right= True 104 | result [8, 9, 0, 1, 2, 3, 4, 5, 6, 7] 105 | 106 | testing: rotate2 ([8, 9, 0, 1, 2, 3, 4, 5, 6, 7], 2) right= False 107 | result [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 108 | 109 | testing: rotate3 ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 132) right= True 110 | result [8, 9, 0, 1, 2, 3, 4, 5, 6, 7] 111 | 112 | testing: rotate3 ([8, 9, 0, 1, 2, 3, 4, 5, 6, 7], 132) right= False 113 | result [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 114 | 115 | ''' 116 | -------------------------------------------------------------------------------- /string/src/compare.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/string/src/compare.jpg -------------------------------------------------------------------------------- /string/src/general.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heqin-zhu/algorithm/61b33a38c49ecdc9f443433ef500aa3f5e8f68e4/string/src/general.jpg -------------------------------------------------------------------------------- /string/sunday.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : sunday.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-07-11 15:26 9 | # Description: 字符串模式匹配, sunday 算法, kmp 的改进 10 | # pattern matching for strings using sunday algorithm 11 | ######################################################################### 12 | ''' 13 | 14 | 15 | def getPos(pattern): 16 | dic = {} 17 | for i, j in enumerate(pattern[::-1]): 18 | if j not in dic: 19 | dic[j] = i 20 | return dic 21 | 22 | 23 | def find(s, p): 24 | dic = getPos(p) 25 | ps = pp = 0 26 | ns = len(s) 27 | np = len(p) 28 | while ps < ns and pp < np: 29 | if s[ps] == p[pp]: 30 | ps, pp = ps+1, pp+1 31 | else: 32 | idx = ps + np-pp 33 | if idx >= ns: 34 | return -1 35 | ch = s[idx] 36 | if ch in dic: 37 | ps += dic[ch]+1-pp 38 | else: 39 | ps = idx+1 40 | pp = 0 41 | if pp == np: 42 | return ps-np 43 | else: 44 | return -1 45 | 46 | 47 | def findAll(s, p): 48 | ns = len(s) 49 | np = len(p) 50 | i = 0 51 | ret = [] 52 | while s: 53 | print(s, p) 54 | tmp = find(s, p) 55 | if tmp == -1: 56 | break 57 | ret.append(i+tmp) 58 | end = tmp+np 59 | i += end 60 | s = s[end:] 61 | return ret 62 | 63 | 64 | def randStr(n=3): 65 | return [randint(ord('a'), ord('z')) for i in range(n)] 66 | 67 | 68 | def test(n): 69 | s = randStr(n) 70 | p = randStr(3) 71 | str_s = ''.join((chr(i) for i in s)) 72 | str_p = ''.join((chr(i) for i in p)) 73 | n1 = find(s, p) 74 | n2 = str_s.find(str_p) # 利用已有的 str find 算法检验 75 | if n1 != n2: 76 | print(n1, n2, str_p, str_s) 77 | return False 78 | return True 79 | 80 | 81 | if __name__ == '__main__': 82 | from random import randint 83 | n = 1000 84 | suc = sum(test(n) for i in range(n)) 85 | print('test {n} times, success {suc} times'.format(n=n, suc=suc)) 86 | -------------------------------------------------------------------------------- /string/wildcard_matching.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | ''' mbinary 3 | ####################################################################### 4 | # File : wildcard_matching.py 5 | # Author: mbinary 6 | # Mail: zhuheqin1@gmail.com 7 | # Blog: https://mbinary.xyz 8 | # Github: https://github.com/mbinary 9 | # Created Time: 2018-12-13 22:46 10 | # Description: 11 | wild card '*' matches 0 or any chars, and '?' matches any single char. 12 | ####################################################################### 13 | ''' 14 | 15 | 16 | ''' 17 | idea 18 | 19 | dynamic programming 20 | 21 | dp[m+1][n+1]: bool 22 | 23 | i:n, j:m 24 | dp[j][i] indicates if s[:i+1] matches p[:j+1] 25 | 26 | initial: dp[0][0] = True, dp[0][i],dp[j][0] = False 27 | only if p startswith '*', dp[1][0] = True. 28 | 29 | if p[j] = '*': dp[j][i] = dp[j-1][i] or dp[j][i-1] 30 | elif p[j] = '?': dp[j][i] = dp[j-1][i-1] 31 | else : dp[j][i] = dp[j-1][i-1] and s[i] == p[j] 32 | ''' 33 | 34 | # leetcode: q44 https://leetcode.com/problems/wildcard-matching/description/ 35 | 36 | 37 | def isMatch(self, s, p): 38 | """ 39 | :type s: str 40 | :type p: str pattern str including wildcard 41 | :rtype: bool 42 | """ 43 | n, m = len(s), len(p) 44 | last = [False]*(n+1) 45 | last[0] = True 46 | for j in range(m): 47 | if p[j] == '*': 48 | for i in range(n): 49 | last[i+1] = last[i+1] or last[i] 50 | elif p[j] == '?': 51 | last.pop() 52 | last.insert(0, False) 53 | else: 54 | li = [False] 55 | for i in range(n): 56 | li.append(last[i] and p[j] == s[i]) 57 | last = li 58 | return last[-1] 59 | -------------------------------------------------------------------------------- /utils/codecogs.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : codecogs.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2019-04-16 09:41 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | import os 13 | import re 14 | import sys 15 | from translate import Translator as TR 16 | 17 | FORMULA = re.compile(r'\${1,2}(?P.+?)\${1,2}', re.DOTALL) 18 | Chinese = re.compile(u"(?P[\u4e00-\u9fa5]+)") 19 | API = 'https://latex.codecogs.com/gif.latex?' 20 | 21 | 22 | def codecog(f): 23 | if os.path.exists(f) and f.endswith('.md'): 24 | with open(f) as fp: 25 | txt = fp.read() 26 | with open(f, 'w') as fp: 27 | fp.write(re.sub(FORMULA, covert, txt)) 28 | else: 29 | s = re.sub(FORMULA, covert, f) 30 | print(s) 31 | 32 | 33 | def covert(matched): 34 | s = matched.group('formula').strip('$ ') 35 | s = re.sub(Chinese, zh2en, s) 36 | s = re.sub(r'\r+|\n+|\\n', ' ', s) 37 | s = re.sub(' +', '&space;', s) 38 | return '![]({})'.format(API+s) 39 | 40 | 41 | def zh2en(txt): 42 | s = txt.group('chinese').strip() 43 | tran = TR(to_lang='en', from_lang='zh') 44 | en = tran.translate(s) 45 | return re.sub(' +', '-', en) 46 | 47 | 48 | def handle(path): 49 | if os.path.isdir(path): 50 | for p, ds, fs in os.walk(path): 51 | for f in fs: 52 | if f.endswith('.md'): 53 | codecog(os.path.join(p, f)) 54 | else: 55 | codecog(path) 56 | 57 | 58 | if __name__ == '__main__': 59 | args = sys.argv[1:] 60 | if not args: 61 | s = input('Input a file: ') 62 | args.append(s) 63 | for f in args: 64 | handle(f) 65 | -------------------------------------------------------------------------------- /utils/config.py: -------------------------------------------------------------------------------- 1 | README = r''' 2 | # Algorithm and data structures 3 | 4 | [![Stars](https://img.shields.io/github/stars/mbinary/algorithm.svg?label=Stars&style=social)](https://github.com/mbinary/algorithm/stargazers) 5 | [![Forks](https://img.shields.io/github/forks/mbinary/algorithm.svg?label=Fork&style=social)](https://github.com/mbinary/algorithm/network/members) 6 | [![repo-size](https://img.shields.io/github/repo-size/mbinary/algorithm.svg)]() 7 | [![License](https://img.shields.io/badge/LICENSE-WTFPL-blue.svg)](LICENSE) 8 | [![Language](https://img.shields.io/badge/language-python3-orange.svg)]() 9 | [![codebeat badge](https://codebeat.co/badges/4ef725b5-405a-4390-a860-a86deefab3f8)](https://codebeat.co/projects/github-com-mbinary-algorithm-master) 10 | 11 | >Notes and codes for learning algorithm and data structures :smiley: 12 | 13 | Some pictures and ideas are from `<>` 14 | 15 | [Click here](./docs) to view notes 16 | # Index 17 | {index} 18 | ''' 19 | 20 | HEAD = '''{begin} mbinary 21 | ######################################################################### 22 | # File : {name} 23 | # Author: mbinary 24 | # Mail: zhuheqin1@gmail.com 25 | # Blog: https://mbinary.xyz 26 | # Github: https://github.com/mbinary 27 | # Created Time: {ctime} 28 | # Description: 29 | ######################################################################### 30 | {end} 31 | ''' 32 | -------------------------------------------------------------------------------- /utils/genReadme.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : genReadme.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-12-11 15:53 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | # coding: utf-8 13 | from tree import tree 14 | from argparse import ArgumentParser 15 | from config import README 16 | 17 | parser = ArgumentParser() 18 | 19 | parser.add_argument('-p', '--path', default='.', help='path to walk') 20 | parser.add_argument('-f', '--fileinclude', action='store_true', 21 | default=True, help='if has, list files and dirs, else only dirs') 22 | parser.add_argument('-d', '--depth', type=int, default=2) 23 | # 获取参数 24 | args = parser.parse_args() 25 | FILE = args.fileinclude 26 | PATH = args.path 27 | DEPTH = args.depth 28 | 29 | 30 | idxs = tree(PATH, DEPTH, FILE) 31 | s = README.format(index='\n'.join(idxs)) 32 | with open('README.md', 'w') as f: 33 | f.write(s) 34 | -------------------------------------------------------------------------------- /utils/headinfo.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : headInfo.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-07-08 14:48 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | 13 | import os 14 | import sys 15 | import time 16 | from config import HEAD 17 | count = 0 18 | 19 | 20 | def handleFile(path): 21 | global count 22 | head = getHead(path) 23 | if head == '': 24 | return 25 | with open(path, 'r', encoding='utf8', errors='ignore') as f: 26 | s = f.read() 27 | if 'mbinary' in s: 28 | return 29 | count += 1 30 | name = os.path.basename(path) 31 | print('[{count}]: Adding head info to {name}'.format(count=count, name=name)) 32 | with open(path, 'w') as f: 33 | f.write(head+s) 34 | 35 | 36 | def getHead(path): 37 | name = os.path.basename(path) 38 | # skip self or hidden file 39 | if name == os.path.basename(__file__) or name[0] == '.': 40 | return '' 41 | suf = name[name.rfind('.')+1:] 42 | begin = end = '' 43 | if suf == 'py': 44 | begin = end = "'''" 45 | elif suf in ['c', 'cc', 'cpp', 'java']: 46 | begin, end = '/*', '*/' 47 | elif suf == 'sh': 48 | begin = end = '#' 49 | else: 50 | return '' 51 | timeStamp = time.localtime(os.stat(path).st_ctime) 52 | ctime = time.strftime('%Y-%m-%d %H:%M', timeStamp) 53 | return HEAD.format(begin=begin, end=end, ctime=ctime, name=name) 54 | 55 | 56 | def handleDir(dirPath): 57 | gen = os.walk(dirPath) 58 | for path, dirs, files in gen: 59 | for f in files: 60 | handleFile(os.path.join(path, f)) 61 | 62 | 63 | if __name__ == '__main__': 64 | works = sys.argv[1:] 65 | if works == []: 66 | works = ['.'] 67 | for one in works: 68 | if not os.path.exists(one): 69 | print('[PathError]: {one} not exists'.format(one=one)) 70 | continue 71 | if os.path.isdir(one): 72 | handleDir(one) 73 | else: 74 | handleFile(one) 75 | -------------------------------------------------------------------------------- /utils/tree.py: -------------------------------------------------------------------------------- 1 | ''' mbinary 2 | ######################################################################### 3 | # File : tree.py 4 | # Author: mbinary 5 | # Mail: zhuheqin1@gmail.com 6 | # Blog: https://mbinary.xyz 7 | # Github: https://github.com/mbinary 8 | # Created Time: 2018-12-11 15:56 9 | # Description: 10 | ######################################################################### 11 | ''' 12 | # coding: utf-8 13 | import os 14 | from argparse import ArgumentParser 15 | 16 | # 命令行输入参数处理 17 | parser = ArgumentParser() 18 | 19 | parser.add_argument('-p', '--path', default='.', help='path to walk') 20 | parser.add_argument('-f', '--fileinclude', action='store_true', 21 | help='if has, list files and dirs, else only dirs') 22 | parser.add_argument('-d', '--depth', type=int, default=2) 23 | # 获取参数 24 | args = parser.parse_args() 25 | FILE = args.fileinclude 26 | PATH = args.path 27 | DEPTH = args.depth 28 | 29 | 30 | def mklink(path): 31 | return '* [{name}]({path})'.format(name=os.path.basename(path), path=path) 32 | 33 | 34 | def clean(paths): 35 | ret = [] 36 | for path in paths: 37 | name = os.path.basename(path) 38 | if not (name.startswith('.') or name.startswith('__')): 39 | ret.append(path) 40 | return ret 41 | 42 | 43 | def tree(path='.', depth=2, showfile=False): 44 | li = [] 45 | if os.path.isdir(path): 46 | li = os.listdir(path) 47 | else: 48 | li = [path] 49 | items = [os.path.join(path, i) for i in li if not i.startswith('.')] 50 | items = clean(items) 51 | items = sorted(items) 52 | if not showfile: 53 | items = [i for i in items if os.path.isdir(i)] 54 | if depth == 1: 55 | return [mklink(path)] + [' '*4 + mklink(i) for i in items] 56 | else: 57 | uls = [tree(i, depth-1, showfile) for i in items] 58 | ret = [' '*4 + li for ul in uls for li in ul] 59 | return [mklink(path)] + ret 60 | 61 | 62 | if __name__ == '__main__': 63 | print('\n'.join(tree(PATH, DEPTH, FILE))) 64 | --------------------------------------------------------------------------------