mirror of
https://github.com/heqin-zhu/algorithm.git
synced 2024-03-22 13:30:46 +08:00
Add number theory, string matching, dynamic programming codes
This commit is contained in:
parent
bbe68d7f4f
commit
273702e4e4
32
README.md
32
README.md
|
@ -17,17 +17,6 @@ So,if you wannt to view the notes which contain latex math formulas and are in m
|
|||
* [.](.)
|
||||
* [README.md](./README.md)
|
||||
* [backtracking](./backtracking)
|
||||
* [computationalMethod](./computationalMethod)
|
||||
* [README.md](./computationalMethod/README.md)
|
||||
* [interplotion.py](./computationalMethod/interplotion.py)
|
||||
* [iteration.py](./computationalMethod/iteration.py)
|
||||
* [least_square.py](./computationalMethod/least_square.py)
|
||||
* [linear_equation.py](./computationalMethod/linear_equation.py)
|
||||
* [numerical_differential.py](./computationalMethod/numerical_differential.py)
|
||||
* [numerical_integration.py](./computationalMethod/numerical_integration.py)
|
||||
* [solve-linear-by-iteration.py](./computationalMethod/solve-linear-by-iteration.py)
|
||||
* [tongyu_equation.py](./computationalMethod/tongyu_equation.py)
|
||||
* [vector_norm.py](./computationalMethod/vector_norm.py)
|
||||
* [dataStructure](./dataStructure)
|
||||
* [allOone](./dataStructure/allOone)
|
||||
* [bTree.py](./dataStructure/bTree.py)
|
||||
|
@ -45,7 +34,7 @@ So,if you wannt to view the notes which contain latex math formulas and are in m
|
|||
* [redBlackTree.py](./dataStructure/redBlackTree.py)
|
||||
* [redBlackTree0.py](./dataStructure/redBlackTree0.py)
|
||||
* [splayTree.py](./dataStructure/splayTree.py)
|
||||
* [trie.py](./dataStructure/trie.py)
|
||||
* [trie](./dataStructure/trie)
|
||||
* [winnerTree.py](./dataStructure/winnerTree.py)
|
||||
* [divideAndConquer](./divideAndConquer)
|
||||
* [min_distance_of_n_points.py](./divideAndConquer/min_distance_of_n_points.py)
|
||||
|
@ -59,6 +48,7 @@ So,if you wannt to view the notes which contain latex math formulas and are in m
|
|||
* [red-black-tree.md](./docs/red-black-tree.md)
|
||||
* [sort.md](./docs/sort.md)
|
||||
* [src](./docs/src)
|
||||
* [string-matching.md](./docs/string-matching.md)
|
||||
* [tree.md](./docs/tree.md)
|
||||
* [dynamicProgramming](./dynamicProgramming)
|
||||
* [Vec2d.hs](./dynamicProgramming/Vec2d.hs)
|
||||
|
@ -66,15 +56,32 @@ So,if you wannt to view the notes which contain latex math formulas and are in m
|
|||
* [matrixChainMultiply.py](./dynamicProgramming/matrixChainMultiply.py)
|
||||
* [splitStripe.hs](./dynamicProgramming/splitStripe.hs)
|
||||
* [splitStripe.py](./dynamicProgramming/splitStripe.py)
|
||||
* [stoneGame.py](./dynamicProgramming/stoneGame.py)
|
||||
* [testVec2d.hs](./dynamicProgramming/testVec2d.hs)
|
||||
* [wildcard_matching.py](./dynamicProgramming/wildcard_matching.py)
|
||||
* [math](./math)
|
||||
* [README.md](./math/README.md)
|
||||
* [euler.py](./math/euler.py)
|
||||
* [factor.py](./math/factor.py)
|
||||
* [gcd.py](./math/gcd.py)
|
||||
* [isPrime.py](./math/isPrime.py)
|
||||
* [modulo_equation.py](./math/modulo_equation.py)
|
||||
* [num_weight.py](./math/num_weight.py)
|
||||
* [permute_back_track.py](./math/permute_back_track.py)
|
||||
* [permute_cantor.c](./math/permute_cantor.c)
|
||||
* [permute_divide_and_conquer.py](./math/permute_divide_and_conquer.py)
|
||||
* [permute_next_arrangement.c](./math/permute_next_arrangement.c)
|
||||
* [primesLEn.hs](./math/primesLEn.hs)
|
||||
* [numericalAnalysis](./numericalAnalysis)
|
||||
* [README.md](./numericalAnalysis/README.md)
|
||||
* [interplotion.py](./numericalAnalysis/interplotion.py)
|
||||
* [iteration.py](./numericalAnalysis/iteration.py)
|
||||
* [least_square.py](./numericalAnalysis/least_square.py)
|
||||
* [linear_equation.py](./numericalAnalysis/linear_equation.py)
|
||||
* [numerical_differential.py](./numericalAnalysis/numerical_differential.py)
|
||||
* [numerical_integration.py](./numericalAnalysis/numerical_integration.py)
|
||||
* [solve-linear-by-iteration.py](./numericalAnalysis/solve-linear-by-iteration.py)
|
||||
* [vector_norm.py](./numericalAnalysis/vector_norm.py)
|
||||
* [search](./search)
|
||||
* [8Astar.py](./search/8Astar.py)
|
||||
* [BFS_knight.hs](./search/BFS_knight.hs)
|
||||
|
@ -96,6 +103,7 @@ So,if you wannt to view the notes which contain latex math formulas and are in m
|
|||
* [rabin_karp.py](./string/rabin_karp.py)
|
||||
* [src](./string/src)
|
||||
* [sunday.py](./string/sunday.py)
|
||||
* [wildcard_matching.py](./string/wildcard_matching.py)
|
||||
* [utils](./utils)
|
||||
* [config.py](./utils/config.py)
|
||||
* [genReadme.py](./utils/genReadme.py)
|
||||
|
|
81
dataStructure/trie/mapSum.py
Normal file
81
dataStructure/trie/mapSum.py
Normal file
|
@ -0,0 +1,81 @@
|
|||
#coding: utf-8
|
||||
''' mbinary
|
||||
#######################################################################
|
||||
# File : mapSum.py
|
||||
# Author: mbinary
|
||||
# Mail: zhuheqin1@gmail.com
|
||||
# Blog: https://mbinary.coding.me
|
||||
# Github: https://github.com/mbinary
|
||||
# Created Time: 2018-12-14 23:11
|
||||
# Description:
|
||||
实现一个 MapSum 类里的两个方法,insert 和 sum。
|
||||
|
||||
对于方法 insert,你将得到一对(字符串,整数)的键值对。字符串表示键,整数表示值。如果键已经存在,那么原来的键值对将被替代成新的键值对。
|
||||
|
||||
对于方法 sum,你将得到一个表示前缀的字符串,你需要返回所有以该前缀开头的键的值的总和。
|
||||
|
||||
示例 1:
|
||||
|
||||
输入: insert("apple", 3), 输出: Null
|
||||
输入: sum("ap"), 输出: 3
|
||||
输入: insert("app", 2), 输出: Null
|
||||
输入: sum("ap"), 输出: 5
|
||||
leetcode-ch:677 https://leetcode-cn.com/problems/map-sum-pairs/
|
||||
#######################################################################
|
||||
'''
|
||||
|
||||
class node:
|
||||
def __init__(self,ch,n=0):
|
||||
self.ch = ch
|
||||
self.n = n
|
||||
self.children={}
|
||||
def __getitem__(self,ch):
|
||||
return self.children[ch]
|
||||
def __setitem__(self,ch,nd):
|
||||
self.children[ch]=nd
|
||||
def __len__(self):
|
||||
return len(self.children)
|
||||
def __iter__(self):
|
||||
return iter(self.children.values())
|
||||
def __delitem(self,ch):
|
||||
del self.children[ch]
|
||||
def __contains__(self,ch):
|
||||
return ch in self.children
|
||||
class MapSum:
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Initialize your data structure here.
|
||||
"""
|
||||
self.root = node('')
|
||||
|
||||
def insert(self, key, val):
|
||||
"""
|
||||
:type key: str
|
||||
:type val: int
|
||||
:rtype: void
|
||||
"""
|
||||
nd = self.root
|
||||
for i in key:
|
||||
if i not in nd:
|
||||
nd[i] = node(i)
|
||||
nd = nd[i]
|
||||
nd.n = val
|
||||
|
||||
def visit(self,nd):
|
||||
ret = nd.n
|
||||
for chd in nd:
|
||||
ret+=self.visit(chd)
|
||||
return ret
|
||||
def sum(self, prefix):
|
||||
"""
|
||||
:type prefix: str
|
||||
:rtype: int
|
||||
"""
|
||||
nd = self.root
|
||||
for ch in prefix:
|
||||
if ch in nd:
|
||||
nd = nd[ch]
|
||||
else:return 0
|
||||
return self.visit(nd)
|
||||
|
110
docs/string-matching.md
Normal file
110
docs/string-matching.md
Normal file
|
@ -0,0 +1,110 @@
|
|||
# String Matching algorithm
|
||||
|
||||
![](https://upload-images.jianshu.io/upload_images/7130568-e10dc137e9083a0e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
|
||||
|
||||
## Rabin-Karp
|
||||
We can view a string of k characters (digits) as a length-k decimal number. E.g., the string “31425” corresponds to the decimal number 31,425.
|
||||
- Given a pattern P [1..m], let p denote the corresponding decimal value.
|
||||
- Given a text T [1..n], let $t_s$ denote the decimal value of the length-m substring T [(s+1)..(s+m)] for s=0,1,…,(n-m).
|
||||
- let `d` be the radix of num, thus $d = len(set(s))$
|
||||
- $t_s$ = p iff T [(s+1)..(s+m)] = P [1..m].
|
||||
- p can be computed in O(m) time. p = P[m] + d\*(P[m-1] + d\*(P[m-2]+…)).
|
||||
- t0 can similarly be computed in O(m) time.
|
||||
- Other $t_1,\ldots,t_{n-m}$ can be computed in O(n-m) time since $t_{s+1} can be computed from ts in constant time.
|
||||
Namely,
|
||||
|
||||
$$
|
||||
t_{s+1} = d*(t_s-d^{m-1} * T[s+1])+T[s+m+1]
|
||||
$$
|
||||
However, it's no need to calculate $t_{s+1}$ directly. We can use modulus operation to reduce the work of caculation.
|
||||
|
||||
We choose a small prime number. Eg 13 for radix( noted as d) 10.
|
||||
Generally, d\*q should fit within one computer word.
|
||||
|
||||
We firstly caculate t0 mod q.
|
||||
Then, for every $t_i (i>1)$
|
||||
assume
|
||||
$$
|
||||
t_{i-1} = T[i+m-1] + 10*T[i+m-2]+\ldots+10^{m-1}*T[i-1]
|
||||
$$
|
||||
denote $ d' = d^{m-1}\ mod\ q$
|
||||
thus,
|
||||
$$
|
||||
\begin{aligned}
|
||||
t_i &= (t_{i-1} - d^{m-1}*T[i-1]) * d + T[i+m]\\
|
||||
&\equiv (t_{i-1} - d^{m-1}*T[i-1]) * d + T[i+m] (mod\ q)\\
|
||||
&\equiv (t_{i-1}- ( d^{m-1} mod \ q) *T[i-1]) * d + T[i+m] (mod\ q)\\
|
||||
&\equiv (t_{i-1}- d'*T[i-1]) * d + T[i+m] (mod\ q)
|
||||
\end{aligned}
|
||||
$$
|
||||
|
||||
So we can compare the modular value of each ti with p's.
|
||||
Only if they are the same, then we compare the origin chracter, namely $T[i],T[i+1],\ldots,T[i+m-1]$ and the pattern.
|
||||
Gernerally, this algorithm's time approximation is O(n+m), and the worst case is O((n-m+1)\*m)
|
||||
|
||||
**Problem: this is assuming p and ts are small numbers. They may be too large to work with easily.**
|
||||
|
||||
## FSM
|
||||
A FSM can be represented as (Q,q0,A,S,C), where
|
||||
- Q is the set of all states
|
||||
- q0 is the start state
|
||||
- $A\in Q$ is a set of accepting states.
|
||||
- S is a finite input alphabet.
|
||||
- C is the set of transition functions: namely $q_j = c(s,q_i)$.
|
||||
|
||||
Given a pattern string S, we can build a FSM for string matching.
|
||||
Assume S has m chars, and there should be m+1 states. One is for the begin state, and the others are for matching state of each position of S.
|
||||
|
||||
Once we have built the FSM, we can run it on any input string.
|
||||
## KMP
|
||||
>Knuth-Morris-Pratt method
|
||||
|
||||
The idea is inspired by FSM. We can avoid computing the transition functions. Instead, we compute a prefix functi`Next` on P in O(m) time, and Next has only m entries.
|
||||
> Prefix funtion stores info about how the pattern matches against shifts of itself.
|
||||
|
||||
- String w is a prefix of string x, if x=wy for some string y
|
||||
- String w is a suffix of string x, if x=yw for some string y
|
||||
- The k-character prefix of the pattern P [1..m] denoted by Pk.
|
||||
- Given that pattern prefix P [1..q] matches text characters T [(s+1)..(s+q)], what is the least shift s'> s such that P [1..k] = T [(s'+1)..(s'+k)] where s'+k=s+q?
|
||||
- At the new shift s', no need to compare the first k characters of P with corresponding characters of T.
|
||||
Method: For prefix pi, find the longest proper prefix of pi that is also a suffix of pi.
|
||||
next[q] = max{k|k\<q and pk is a suffix of pq}
|
||||
|
||||
For example: p = ababaca, for p5 = ababa, Next[5] = 3. Namely p3=aba is the longest prefix of p that is also a suffix of p5.
|
||||
|
||||
Time approximation: finding prefix function `next` take O(m), matching takes O(m+n)
|
||||
|
||||
## Boyer-Moore
|
||||
- The longer the pattern is, the faster it works.
|
||||
- Starts from the end of pattern, while KMP starts from the beginning.
|
||||
- Works best for character string, while KMP works best for binary string.
|
||||
- KMP and Boyer-Moore
|
||||
- Preprocessing existing patterns.
|
||||
- Searching patterns in input strings.
|
||||
## Sunday
|
||||
### features
|
||||
- simplification of the Boyer-Moore algorithm;
|
||||
- uses only the bad-character shift;
|
||||
- easy to implement;
|
||||
- preprocessing phase in O(m+sigma) time and O(sigma) space complexity;
|
||||
- searching phase in O(mn) time complexity;
|
||||
- very fast in practice for short patterns and large alphabets.
|
||||
### description
|
||||
The Quick Search algorithm uses only the bad-character shift table (see chapter Boyer-Moore algorithm). After an attempt where the window is positioned on the text factor y[j .. j+m-1], the length of the shift is at least equal to one. So, the character y[j+m] is necessarily involved in the next attempt, and thus can be used for the bad-character shift of the current attempt.
|
||||
|
||||
The bad-character shift of the present algorithm is slightly modified to take into account the last character of x as follows: for c in Sigma, qsBc[c]=min{i : 0 < i leq m and x[m-i]=c} if c occurs in x, m+1 otherwise (thanks to Darko Brljak).
|
||||
|
||||
The preprocessing phase is in O(m+sigma) time and O(sigma) space complexity.
|
||||
|
||||
During the searching phase the comparisons between pattern and text characters during each attempt can be done in any order. The searching phase has a quadratic worst case time complexity but it has a good practical behaviour.
|
||||
|
||||
For instance,
|
||||
![image.png](https://upload-images.jianshu.io/upload_images/7130568-76d130ae24603d51.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
|
||||
|
||||
In this example, t0, ..., t4 = a b c a b is the current text window that is compared with the pattern. Its suffix a b has matched, but the comparison c-a causes a mismatch. The bad-character heuristics of the Boyer-Moore algorithm (a) uses the "bad" text character c to determine the shift distance. The Horspool algorithm (b) uses the rightmost character b of the current text window. The Sunday algorithm (c) uses the character directly right of the text window, namely d in this example. Since d does not occur in the pattern at all, the pattern can be shifted past this position.
|
||||
|
||||
|
||||
# Reference:
|
||||
1. Xuyun, ppt, String matching
|
||||
2. [Sunday-algorithm](http://www.inf.fh-flensburg.de/lang/algorithmen/pattern/sunday.htm)
|
||||
3. GeeksforGeeks, [KMP Algorithm](https://www.geeksforgeeks.org/kmp-algorithm-for-pattern-searching/)
|
36
dynamicProgramming/stoneGame.py
Normal file
36
dynamicProgramming/stoneGame.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
#coding: utf-8
|
||||
''' mbinary
|
||||
#######################################################################
|
||||
# File : stoneGame.py
|
||||
# Author: mbinary
|
||||
# Mail: zhuheqin1@gmail.com
|
||||
# Blog: https://mbinary.coding.me
|
||||
# Github: https://github.com/mbinary
|
||||
# Created Time: 2018-12-14 14:32
|
||||
# Description:
|
||||
亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] 。游戏以谁手中的石子最多来决出胜负。石子的总数是奇数,所以没有平局。
|
||||
亚历克斯和李轮流进行. 每回合,玩家从行的开始或结束处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止,此时手中石子最多的玩家获胜。
|
||||
那么先手一定会赢吗? 是的, 求出先手比后手多的石子数.
|
||||
leetcode-cn 877: https://leetcode-cn.com/problems/stone-game/
|
||||
#######################################################################
|
||||
'''
|
||||
def stoneGame(li):
|
||||
'''li: list, len(li)%2==0, sum(li)%2==1'''
|
||||
def f(p,q):
|
||||
ret = dp[p][q]
|
||||
if ret is None:
|
||||
if p+1==q:
|
||||
ret = abs(li[p]-li[q])
|
||||
else:
|
||||
# max min
|
||||
# take the first one
|
||||
n1 = li[p] + min(-li[p+1]+f(p+2,q),-li[q]+f(p+1,q-1))
|
||||
# take the last one
|
||||
n2 = li[q] + min(-li[p]+f(p+1,q-1),-li[q-1]+f(p,q-2))
|
||||
ret = max(n1,n2)
|
||||
dp[p][q] = ret
|
||||
#print(li[p:q+1],ret)
|
||||
return ret
|
||||
n = len(li)
|
||||
dp = [[None for i in range(n)] for i in range(n)]
|
||||
return f(0,n-1)
|
57
dynamicProgramming/wildcard_matching.py
Normal file
57
dynamicProgramming/wildcard_matching.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
#coding: utf-8
|
||||
''' mbinary
|
||||
#######################################################################
|
||||
# File : wildcard_matching.py
|
||||
# Author: mbinary
|
||||
# Mail: zhuheqin1@gmail.com
|
||||
# Blog: https://mbinary.coding.me
|
||||
# Github: https://github.com/mbinary
|
||||
# Created Time: 2018-12-13 22:46
|
||||
# Description:
|
||||
wild card '*' matches 0 or any chars, and '?' matches any single char.
|
||||
#######################################################################
|
||||
'''
|
||||
|
||||
|
||||
'''
|
||||
idea
|
||||
|
||||
dynamic programming
|
||||
|
||||
dp[m+1][n+1]: bool
|
||||
|
||||
i:n, j:m
|
||||
dp[j][i] indicates if s[:i+1] matches p[:j+1]
|
||||
|
||||
initial: dp[0][0] = True, dp[0][i],dp[j][0] = False
|
||||
only if p startswith '*', dp[1][0] = True.
|
||||
|
||||
if p[j] = '*': dp[j][i] = dp[j-1][i] or dp[j][i-1]
|
||||
elif p[j] = '?': dp[j][i] = dp[j-1][i-1]
|
||||
else : dp[j][i] = dp[j-1][i-1] and s[i] == p[j]
|
||||
'''
|
||||
|
||||
# leetcode: q44 https://leetcode.com/problems/wildcard-matching/description/
|
||||
|
||||
def isMatch(self, s, p):
|
||||
"""
|
||||
:type s: str
|
||||
:type p: str pattern str including wildcard
|
||||
:rtype: bool
|
||||
"""
|
||||
n,m = len(s),len(p)
|
||||
last = [False]*(n+1)
|
||||
last[0] = True
|
||||
for j in range(m):
|
||||
if p[j]=='*':
|
||||
for i in range(n):
|
||||
last[i+1] = last[i+1] or last[i]
|
||||
elif p[j]=='?':
|
||||
last.pop()
|
||||
last.insert(0,False)
|
||||
else:
|
||||
li = [False]
|
||||
for i in range(n):
|
||||
li.append( last[i] and p[j]==s[i])
|
||||
last = li
|
||||
return last[-1]
|
32
math/README.md
Normal file
32
math/README.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
# Number Theory
|
||||
>See more details on [my blog](https://mbinary.coding.me/number-theory.html)
|
||||
|
||||
## gcd.py
|
||||
- gcd(a,b)
|
||||
- xgcd(a,b): return gcd(a,b),x,y, where ax+by = gcd(a,b)
|
||||
|
||||
## isPrime
|
||||
- isPrime(n): using Miller-Rabin primalrity test.
|
||||
- primeSieve
|
||||
|
||||
## euler.py
|
||||
- phi(n): euler function
|
||||
- sigma(n): return the sum of all factors of n
|
||||
|
||||
## factor.py
|
||||
- factor(n): return a list of numbers that are the factorization of n
|
||||
|
||||
## modulo_equation.py
|
||||
Solving modulo equations
|
||||
|
||||
```python
|
||||
solver = solve()
|
||||
res = solver.solveLinear(3,6,9)
|
||||
|
||||
res = solver.solveHigh(1,8,3,11)
|
||||
|
||||
res = solver.solveGroup([(5,11,2),(3,8,5),(4,1,7)])
|
||||
```
|
||||
|
||||
# Permutation
|
||||
|
33
math/euler.py
Normal file
33
math/euler.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
#coding: utf-8
|
||||
''' mbinary
|
||||
#######################################################################
|
||||
# File : euler.py
|
||||
# Author: mbinary
|
||||
# Mail: zhuheqin1@gmail.com
|
||||
# Blog: https://mbinary.coding.me
|
||||
# Github: https://github.com/mbinary
|
||||
# Created Time: 2018-12-16 10:53
|
||||
# Description:
|
||||
euler function: phi(n)
|
||||
perfect num: \sigma (n) = 2n, \sigma (n) is the sum of all factors of n
|
||||
eg \sigma (9) = 3+3+9 = 15
|
||||
#######################################################################
|
||||
'''
|
||||
from factor import factor
|
||||
from collections import Counter
|
||||
from functools import reduce
|
||||
from operator import mul
|
||||
def phi(n):
|
||||
st = set(factor(n))
|
||||
return round(reduce(mul,(1-1/p for p in st),n))
|
||||
|
||||
def sigma(n):
|
||||
ct = Counter(factor(n))
|
||||
return reduce(mul,(round((p**(ct[p]+1)-1)/(p-1)) for p in ct),1)
|
||||
|
||||
if __name__=='__main__':
|
||||
while 1:
|
||||
n = int(input('n: '))
|
||||
print('phi(n):',phi(n))
|
||||
print('sigma(n):',sigma(n))
|
||||
|
43
math/factor.py
Normal file
43
math/factor.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
#coding: utf-8
|
||||
''' mbinary
|
||||
#######################################################################
|
||||
# File : factorize.py
|
||||
# Author: mbinary
|
||||
# Mail: zhuheqin1@gmail.com
|
||||
# Blog: https://mbinary.coding.me
|
||||
# Github: https://github.com/mbinary
|
||||
# Created Time: 2018-12-16 09:36
|
||||
# Description: factorization, using pollard's rho algorithm and miller-rabin primality test
|
||||
#######################################################################
|
||||
'''
|
||||
|
||||
from random import randint
|
||||
from isPrime import isPrime
|
||||
from gcd import gcd
|
||||
|
||||
def factor(n):
|
||||
'''pollard's rho algorithm'''
|
||||
if n<1:raise Exception('[Error]: {} is less than 1'.format(n))
|
||||
if n==1: return []
|
||||
if isPrime(n):return [n]
|
||||
fact=1
|
||||
cycle_size=2
|
||||
x = x_fixed = 2
|
||||
c = randint(1,n)
|
||||
while fact==1:
|
||||
for i in range(cycle_size):
|
||||
if fact>1:break
|
||||
x=(x*x+c)%n
|
||||
if x==x_fixed:
|
||||
c = randint(1,n)
|
||||
continue
|
||||
fact = gcd(x-x_fixed,n)
|
||||
cycle_size *=2
|
||||
x_fixed = x
|
||||
return factor(fact)+factor(n//fact)
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
while 1:
|
||||
n = int(input('n: '))
|
||||
print(factor(n))
|
33
math/gcd.py
Normal file
33
math/gcd.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
#coding: utf-8
|
||||
''' mbinary
|
||||
#######################################################################
|
||||
# File : gcd.py
|
||||
# Author: mbinary
|
||||
# Mail: zhuheqin1@gmail.com
|
||||
# Blog: https://mbinary.coding.me
|
||||
# Github: https://github.com/mbinary
|
||||
# Created Time: 2018-12-16 10:06
|
||||
# Description:
|
||||
#######################################################################
|
||||
'''
|
||||
|
||||
def gcd(a,b):
|
||||
while b!=0:
|
||||
a,b=b,a%b
|
||||
return a
|
||||
|
||||
def lcm(a,b):
|
||||
return int(a*b/gcd(a,b))
|
||||
def xgcd(a,b):
|
||||
'''return gcd(a,b), x,y where ax+by=gcd(a,b)'''
|
||||
if b==0:return a,1,0
|
||||
g,x,y = xgcd(b,a%b)
|
||||
return g,y,x-a//b*y
|
||||
|
||||
if __name__=='__main__':
|
||||
while 1:
|
||||
a = int(input('a: '))
|
||||
b = int(input('b: '))
|
||||
print('gcd :',gcd(a,b))
|
||||
print('xgcd:',xgcd(a,b))
|
||||
|
120
math/isPrime.py
120
math/isPrime.py
|
@ -5,40 +5,104 @@
|
|||
# Mail: zhuheqin1@gmail.com
|
||||
# Blog: https://mbinary.coding.me
|
||||
# Github: https://github.com/mbinary
|
||||
# Created Time: 2018-05-19 21:34
|
||||
# Created Time: 2018-03-04 21:34
|
||||
# Description:
|
||||
#########################################################################
|
||||
'''
|
||||
|
||||
# created by mbinary @2018-3-4
|
||||
# description: judge a num if it's a prime. It will be more efficient when judging many times
|
||||
from random import randint
|
||||
|
||||
|
||||
primes = [2,3,5,7,11,13]
|
||||
def isPrime(x):
|
||||
global primes
|
||||
if x>primes[-1]:
|
||||
return genPrime(x)
|
||||
return twoDivideFind(x,primes)
|
||||
def quickMulMod(a,b,m):
|
||||
'''a*b%m, quick'''
|
||||
ret = 0
|
||||
while b:
|
||||
if b&1:
|
||||
ret = (a+ret)%m
|
||||
b//=2
|
||||
a = (a+a)%m
|
||||
return ret
|
||||
|
||||
def genPrime(x):
|
||||
global primes
|
||||
while x>primes[-1]:
|
||||
left = primes[-1]
|
||||
right = (left+1)**2
|
||||
lst = []
|
||||
for i in range(left,right):
|
||||
for j in primes:
|
||||
if i%j==0:break
|
||||
else:lst.append(i)
|
||||
primes+=lst
|
||||
else:return twoDivideFind(x,lst)
|
||||
def quickPowMod(a,b,m):
|
||||
'''a^b %m, quick, O(logn)'''
|
||||
ret =1
|
||||
while b:
|
||||
if b&1:
|
||||
ret =quickMulMod(ret,a,m)
|
||||
b//=2
|
||||
a = quickMulMod(a,a,m)
|
||||
return ret
|
||||
|
||||
def twoDivideFind(x,primes):
|
||||
a,b = 0, len(primes)
|
||||
|
||||
def isPrime(n,t=5):
|
||||
'''miller rabin primality test, a probability result
|
||||
t is the number of iteration(witness)
|
||||
'''
|
||||
t = min(n-3,t)
|
||||
if n<2:
|
||||
print('[Error]: {} can\'t be classed with prime or composite'.format(n))
|
||||
return
|
||||
if n==2: return True
|
||||
d = n-1
|
||||
r = 0
|
||||
while d%2==0:
|
||||
r+=1
|
||||
d//=2
|
||||
tested=set()
|
||||
for i in range(t):
|
||||
a = randint(2,n-2)
|
||||
while a in tested:
|
||||
a = randint(2,n-2)
|
||||
tested.add(a)
|
||||
x= quickPowMod(a,d,n)
|
||||
if x==1 or x==n-1: continue #success,
|
||||
for j in range(r-1):
|
||||
x= quickMulMod(x,x,n)
|
||||
if x==n-1:break
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
'''
|
||||
we shouldn't use Fermat's little theory
|
||||
Namyly:
|
||||
For a prime p, and any number a where (a,n)=1
|
||||
a ^(p-1) \equiv 1 (mod p)
|
||||
|
||||
The inverse theorem of it is not True.
|
||||
|
||||
a counter-example: 2^340 \equiv 1 (mod 341), but 341 is a composite
|
||||
'''
|
||||
|
||||
class primeSieve:
|
||||
'''sieve of Eratosthenes, It will be more efficient when judging many times'''
|
||||
primes = [2,3,5,7,11,13]
|
||||
def isPrime(self,x):
|
||||
if x<=primes[-1]:
|
||||
return twoDivideFind(x,self.primes)
|
||||
while x>self.primes[-1]:
|
||||
left = self.primes[-1]
|
||||
right = (left+1)**2
|
||||
lst = []
|
||||
for i in range(left,right):
|
||||
for j in self.primes:
|
||||
if i%j==0:break
|
||||
else:lst.append(i)
|
||||
self.primes+=lst
|
||||
return twoDivideFind(x,lst)
|
||||
|
||||
def twoDivideFind(x,li):
|
||||
a,b = 0, len(li)
|
||||
while a<=b:
|
||||
mid = (a+b)//2
|
||||
if primes[mid]<x:a=mid+1
|
||||
elif primes[mid]>x: b= mid-1
|
||||
else:return True
|
||||
return False
|
||||
if li[mid]<x:a=mid+1
|
||||
elif li[mid]>x: b= mid-1
|
||||
else:return mid
|
||||
return -1
|
||||
|
||||
if __name__=='__main__':
|
||||
n = 100
|
||||
print('prime numbers below',n)
|
||||
print([i for i in range(n) if isPrime(i)])
|
||||
while 1:
|
||||
n = int(input('n: '))
|
||||
print(isPrime(n))
|
||||
|
|
|
@ -1,58 +1,22 @@
|
|||
''' mbinary
|
||||
#########################################################################
|
||||
# File : tongyu_equation.py
|
||||
# File : modulo_equation.py
|
||||
# Author: mbinary
|
||||
# Mail: zhuheqin1@gmail.com
|
||||
# Blog: https://mbinary.coding.me
|
||||
# Github: https://github.com/mbinary
|
||||
# Created Time: 2018-10-02 21:14
|
||||
# Created Time: 2018-3-4 21:14
|
||||
# Description:
|
||||
`--` represents modulo symbol
|
||||
#########################################################################
|
||||
'''
|
||||
|
||||
# created by mbinary @2018-3-4
|
||||
# description: solve tongyu equation
|
||||
# notice that i use -- to repr tongyu symbol
|
||||
|
||||
from isPrime import isPrime,primes
|
||||
from operator import mul, and_
|
||||
from functools import reduce,partial
|
||||
import re
|
||||
|
||||
|
||||
def primeFactoize(x):
|
||||
'''质因数分解 , ret {p:r}'''
|
||||
if isPrime(x):return {x:1}
|
||||
mp={}
|
||||
for i in primes:
|
||||
if x==1:break
|
||||
ct=0
|
||||
while x%i==0:
|
||||
ct+=1
|
||||
x//=i
|
||||
if ct!=0:mp[i]=ct
|
||||
return mp
|
||||
def xgcd(a,b):
|
||||
'''ax+by=gcd(a,b) ,用辗转相除法得到gcd,x,y'''
|
||||
def _xgcd(a,b):
|
||||
if b==0:return a,1,0
|
||||
gcd,x,y=_xgcd(b,a%b)
|
||||
return gcd,y,x-y*a//b
|
||||
if a<b:
|
||||
g,x,y = _xgcd(b,a)
|
||||
return g,y,x
|
||||
return _xgcd(a,b)
|
||||
|
||||
def gcd(a,b):
|
||||
return a if b==0 else gcd(b,a%b)
|
||||
|
||||
def lcm(a,b):
|
||||
return a*b//gcd(a,b)
|
||||
|
||||
def euler(x):
|
||||
mp = primeFactoize(x)
|
||||
fac = [1-1/i for i in mp]
|
||||
return round(reduce(mul,fac,x))
|
||||
from gcd import xgcd
|
||||
from euler import phi
|
||||
from isPrime import isPrime
|
||||
from factor import factor
|
||||
|
||||
def ind(m,g):
|
||||
''' mod m ,primary root g -> {n:indg n}'''
|
||||
|
@ -61,22 +25,20 @@ def ind(m,g):
|
|||
|
||||
def gs(m,num=100):
|
||||
'''return list of m's primary roots below num'''
|
||||
phi = euler(m)
|
||||
mp = primeFactoize(phi)
|
||||
checkLst = [phi//i for i in mp]
|
||||
return [i for i in range(2,num) \
|
||||
if reduce(and_,[(i**n-1)%m !=0 for n in checkLst])]
|
||||
p = phi(m)
|
||||
mp = factor(p)
|
||||
checkLst = [p//i for i in mp]
|
||||
return [i for i in range(2,num) if all((i**n-1)%m !=0 for n in checkLst)]
|
||||
|
||||
def minG(m):
|
||||
phi = euler(m)
|
||||
mp = primeFactoize(phi)
|
||||
checkLst = [phi//i for i in mp]
|
||||
p = phi(m)
|
||||
mp = factor(p)
|
||||
checkLst = [p//i for i in mp]
|
||||
i=2
|
||||
while 1:
|
||||
if reduce(and_,[(i**n-1)%m !=0 for n in checkLst]):return i
|
||||
if all((i**n-1)%m !=0 for n in checkLst):return i
|
||||
i+=1
|
||||
|
||||
|
||||
class solve:
|
||||
def __init__(self,equ=None):
|
||||
self.linearPat= re.compile(r'\s*(\d+)\s*--\s*(\d+)[\s\(]*mod\s*(\d+)')
|
||||
|
@ -87,8 +49,6 @@ class solve:
|
|||
print('equation {equ} has no solution'.format(equ=self.equ))
|
||||
def error(self):
|
||||
print("Error! The divisor m must be postive integer")
|
||||
|
||||
|
||||
def solveLinear(self,a,b,m):
|
||||
'''ax--b(mod m): solve linear equation with one unknown
|
||||
return ([x1,x2,...],m)
|
||||
|
@ -100,7 +60,9 @@ class solve:
|
|||
return None
|
||||
sol=x*b//g
|
||||
m0 = m//g
|
||||
return ([(sol+i*m0)%m for i in range(g)],m)
|
||||
sols = [(sol+i*m0)%m for i in range(g)]
|
||||
print('{}x--{}(mod {}), solution: {} mod {}'.format(a,b,m,sols,m))
|
||||
return (sols,m)
|
||||
def check(self,a,b,m):
|
||||
if m<=0:
|
||||
self.error()
|
||||
|
@ -109,46 +71,46 @@ class solve:
|
|||
if b<0:b+= -b//m * m
|
||||
return a,b,m
|
||||
|
||||
|
||||
#def solvePoly(self,m,mp):
|
||||
''' mod m, mp:{index:coef} is a dict of the polynomials' coefficient and index'''
|
||||
''' g = minG(m)
|
||||
ind_mp = ind(m,g)
|
||||
li = []
|
||||
for i in mp:
|
||||
solve
|
||||
'''
|
||||
|
||||
def solveHigh(self,a,n,b,m):
|
||||
''' ax^n -- b (mod m) ind_mp is a dict of m's {n: indg n}'''
|
||||
ind_mp = ind(m,minG(m))
|
||||
tmp = ind_mp[b] - ind_mp[a]
|
||||
if tmp < 0:tmp+=m
|
||||
print(n,tmp)
|
||||
sol = self.solveLinear(n,tmp,euler(m))
|
||||
sol = self.solveLinear(n,tmp,phi(m))
|
||||
re_mp = {j:i for i ,j in ind_mp.items()}
|
||||
print(sol)
|
||||
return [re_mp[i] for i in sol[0]],m
|
||||
sols = [re_mp[i] for i in sol[0]]
|
||||
print('{}x^{}--{}(mod {}), solution: {} mod {}'.format(a,n,b,m,sols,m))
|
||||
return sols,m
|
||||
|
||||
def solveGroup(tups):
|
||||
def solveGroup(self,tups):
|
||||
'''tups is a list of tongyu equation groups, like
|
||||
[(a1,b1,m1),(a2,b2,m2)...]
|
||||
and, m1,m2... are all primes
|
||||
'''
|
||||
mp = {}
|
||||
print('solving group of equations: ')
|
||||
for a,b,m in tups:
|
||||
print('{}x--{}(mod {})'.format(a,b,m))
|
||||
if m in mp:
|
||||
if mp[m][0]*b!=mp[m][1]*a:
|
||||
self.noSol()
|
||||
return
|
||||
else:mp[m] = (a,b)
|
||||
product= reduce(lambda i,j:i*j, mp.keys(), 1)
|
||||
sol = 0
|
||||
product = 1
|
||||
for i in mp.keys():
|
||||
product *=i
|
||||
sol = [0]
|
||||
for i in mp:
|
||||
x = self.solveLinear(product//i*mp[i][0],1,i)
|
||||
sol+= x*product//i*mp[i][1]
|
||||
sol%=m
|
||||
return ([sol],m)
|
||||
xs,m = self.solveLinear(product//i*mp[i][0],1,i)
|
||||
new = []
|
||||
for x in xs:
|
||||
cur = x*product//i*mp[i][1]
|
||||
for old in sol:
|
||||
new.append(old+cur)
|
||||
sol = new
|
||||
sol= [i%product for i in sol]
|
||||
print('final solution: {} mod {}'.format(sol,product))
|
||||
return sol,product
|
||||
def __call__(self):
|
||||
s=input('输入同余方程,用--代表同于号,形如3--5(mod 7)代表3x模7同余于5')
|
||||
li= self.linearPat.findall(s)
|
||||
|
@ -159,5 +121,7 @@ class solve:
|
|||
if __name__ == '__main__':
|
||||
solver = solve()
|
||||
res = solver.solveLinear(3,6,9)
|
||||
print(res)
|
||||
print(solver.solveHigh(1,8,3,11))
|
||||
print()
|
||||
res = solver.solveHigh(1,8,3,11)
|
||||
print()
|
||||
res = solver.solveGroup([(5,11,2),(3,8,5),(4,1,7)])
|
|
@ -30,7 +30,7 @@ def findAll(s,p):
|
|||
d+=1
|
||||
sm = 0
|
||||
for c in p:
|
||||
if c not in dic:return [-1]
|
||||
if c not in dic:return []
|
||||
sm = sm*d+dic[c]
|
||||
|
||||
ret = []
|
||||
|
|
57
string/wildcard_matching.py
Normal file
57
string/wildcard_matching.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
#coding: utf-8
|
||||
''' mbinary
|
||||
#######################################################################
|
||||
# File : wildcard_matching.py
|
||||
# Author: mbinary
|
||||
# Mail: zhuheqin1@gmail.com
|
||||
# Blog: https://mbinary.coding.me
|
||||
# Github: https://github.com/mbinary
|
||||
# Created Time: 2018-12-13 22:46
|
||||
# Description:
|
||||
wild card '*' matches 0 or any chars, and '?' matches any single char.
|
||||
#######################################################################
|
||||
'''
|
||||
|
||||
|
||||
'''
|
||||
idea
|
||||
|
||||
dynamic programming
|
||||
|
||||
dp[m+1][n+1]: bool
|
||||
|
||||
i:n, j:m
|
||||
dp[j][i] indicates if s[:i+1] matches p[:j+1]
|
||||
|
||||
initial: dp[0][0] = True, dp[0][i],dp[j][0] = False
|
||||
only if p startswith '*', dp[1][0] = True.
|
||||
|
||||
if p[j] = '*': dp[j][i] = dp[j-1][i] or dp[j][i-1]
|
||||
elif p[j] = '?': dp[j][i] = dp[j-1][i-1]
|
||||
else : dp[j][i] = dp[j-1][i-1] and s[i] == p[j]
|
||||
'''
|
||||
|
||||
# leetcode: q44 https://leetcode.com/problems/wildcard-matching/description/
|
||||
|
||||
def isMatch(self, s, p):
|
||||
"""
|
||||
:type s: str
|
||||
:type p: str pattern str including wildcard
|
||||
:rtype: bool
|
||||
"""
|
||||
n,m = len(s),len(p)
|
||||
last = [False]*(n+1)
|
||||
last[0] = True
|
||||
for j in range(m):
|
||||
if p[j]=='*':
|
||||
for i in range(n):
|
||||
last[i+1] = last[i+1] or last[i]
|
||||
elif p[j]=='?':
|
||||
last.pop()
|
||||
last.insert(0,False)
|
||||
else:
|
||||
li = [False]
|
||||
for i in range(n):
|
||||
li.append( last[i] and p[j]==s[i])
|
||||
last = li
|
||||
return last[-1]
|
Loading…
Reference in New Issue
Block a user