Add number theory, string matching, dynamic programming codes

This commit is contained in:
mbinary 2018-12-16 17:09:54 +08:00
parent bbe68d7f4f
commit 273702e4e4
23 changed files with 638 additions and 120 deletions

View File

@ -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)

View 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
View 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/)

View 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)

View 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
View 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
View 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
View 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
View 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))

View File

@ -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))

View File

@ -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)])

View File

@ -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 = []

View 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]