Add number theory, string matching, dynamic programming codes
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)
|
* [README.md](./README.md)
|
||||||
* [backtracking](./backtracking)
|
* [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)
|
* [dataStructure](./dataStructure)
|
||||||
* [allOone](./dataStructure/allOone)
|
* [allOone](./dataStructure/allOone)
|
||||||
* [bTree.py](./dataStructure/bTree.py)
|
* [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)
|
* [redBlackTree.py](./dataStructure/redBlackTree.py)
|
||||||
* [redBlackTree0.py](./dataStructure/redBlackTree0.py)
|
* [redBlackTree0.py](./dataStructure/redBlackTree0.py)
|
||||||
* [splayTree.py](./dataStructure/splayTree.py)
|
* [splayTree.py](./dataStructure/splayTree.py)
|
||||||
* [trie.py](./dataStructure/trie.py)
|
* [trie](./dataStructure/trie)
|
||||||
* [winnerTree.py](./dataStructure/winnerTree.py)
|
* [winnerTree.py](./dataStructure/winnerTree.py)
|
||||||
* [divideAndConquer](./divideAndConquer)
|
* [divideAndConquer](./divideAndConquer)
|
||||||
* [min_distance_of_n_points.py](./divideAndConquer/min_distance_of_n_points.py)
|
* [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)
|
* [red-black-tree.md](./docs/red-black-tree.md)
|
||||||
* [sort.md](./docs/sort.md)
|
* [sort.md](./docs/sort.md)
|
||||||
* [src](./docs/src)
|
* [src](./docs/src)
|
||||||
|
* [string-matching.md](./docs/string-matching.md)
|
||||||
* [tree.md](./docs/tree.md)
|
* [tree.md](./docs/tree.md)
|
||||||
* [dynamicProgramming](./dynamicProgramming)
|
* [dynamicProgramming](./dynamicProgramming)
|
||||||
* [Vec2d.hs](./dynamicProgramming/Vec2d.hs)
|
* [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)
|
* [matrixChainMultiply.py](./dynamicProgramming/matrixChainMultiply.py)
|
||||||
* [splitStripe.hs](./dynamicProgramming/splitStripe.hs)
|
* [splitStripe.hs](./dynamicProgramming/splitStripe.hs)
|
||||||
* [splitStripe.py](./dynamicProgramming/splitStripe.py)
|
* [splitStripe.py](./dynamicProgramming/splitStripe.py)
|
||||||
|
* [stoneGame.py](./dynamicProgramming/stoneGame.py)
|
||||||
* [testVec2d.hs](./dynamicProgramming/testVec2d.hs)
|
* [testVec2d.hs](./dynamicProgramming/testVec2d.hs)
|
||||||
|
* [wildcard_matching.py](./dynamicProgramming/wildcard_matching.py)
|
||||||
* [math](./math)
|
* [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)
|
* [isPrime.py](./math/isPrime.py)
|
||||||
|
* [modulo_equation.py](./math/modulo_equation.py)
|
||||||
* [num_weight.py](./math/num_weight.py)
|
* [num_weight.py](./math/num_weight.py)
|
||||||
* [permute_back_track.py](./math/permute_back_track.py)
|
* [permute_back_track.py](./math/permute_back_track.py)
|
||||||
* [permute_cantor.c](./math/permute_cantor.c)
|
* [permute_cantor.c](./math/permute_cantor.c)
|
||||||
* [permute_divide_and_conquer.py](./math/permute_divide_and_conquer.py)
|
* [permute_divide_and_conquer.py](./math/permute_divide_and_conquer.py)
|
||||||
* [permute_next_arrangement.c](./math/permute_next_arrangement.c)
|
* [permute_next_arrangement.c](./math/permute_next_arrangement.c)
|
||||||
* [primesLEn.hs](./math/primesLEn.hs)
|
* [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)
|
* [search](./search)
|
||||||
* [8Astar.py](./search/8Astar.py)
|
* [8Astar.py](./search/8Astar.py)
|
||||||
* [BFS_knight.hs](./search/BFS_knight.hs)
|
* [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)
|
* [rabin_karp.py](./string/rabin_karp.py)
|
||||||
* [src](./string/src)
|
* [src](./string/src)
|
||||||
* [sunday.py](./string/sunday.py)
|
* [sunday.py](./string/sunday.py)
|
||||||
|
* [wildcard_matching.py](./string/wildcard_matching.py)
|
||||||
* [utils](./utils)
|
* [utils](./utils)
|
||||||
* [config.py](./utils/config.py)
|
* [config.py](./utils/config.py)
|
||||||
* [genReadme.py](./utils/genReadme.py)
|
* [genReadme.py](./utils/genReadme.py)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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/)
|
|
@ -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)
|
|
@ -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]
|
|
@ -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
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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))
|
|
@ -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
|
# Mail: zhuheqin1@gmail.com
|
||||||
# Blog: https://mbinary.coding.me
|
# Blog: https://mbinary.coding.me
|
||||||
# Github: https://github.com/mbinary
|
# Github: https://github.com/mbinary
|
||||||
# Created Time: 2018-05-19 21:34
|
# Created Time: 2018-03-04 21:34
|
||||||
# Description:
|
# Description:
|
||||||
#########################################################################
|
#########################################################################
|
||||||
'''
|
'''
|
||||||
|
from random import randint
|
||||||
# created by mbinary @2018-3-4
|
|
||||||
# description: judge a num if it's a prime. It will be more efficient when judging many times
|
|
||||||
|
|
||||||
|
|
||||||
primes = [2,3,5,7,11,13]
|
def quickMulMod(a,b,m):
|
||||||
def isPrime(x):
|
'''a*b%m, quick'''
|
||||||
global primes
|
ret = 0
|
||||||
if x>primes[-1]:
|
while b:
|
||||||
return genPrime(x)
|
if b&1:
|
||||||
return twoDivideFind(x,primes)
|
ret = (a+ret)%m
|
||||||
|
b//=2
|
||||||
|
a = (a+a)%m
|
||||||
|
return ret
|
||||||
|
|
||||||
def genPrime(x):
|
def quickPowMod(a,b,m):
|
||||||
global primes
|
'''a^b %m, quick, O(logn)'''
|
||||||
while x>primes[-1]:
|
ret =1
|
||||||
left = primes[-1]
|
while b:
|
||||||
right = (left+1)**2
|
if b&1:
|
||||||
lst = []
|
ret =quickMulMod(ret,a,m)
|
||||||
for i in range(left,right):
|
b//=2
|
||||||
for j in primes:
|
a = quickMulMod(a,a,m)
|
||||||
if i%j==0:break
|
return ret
|
||||||
else:lst.append(i)
|
|
||||||
primes+=lst
|
|
||||||
else:return twoDivideFind(x,lst)
|
|
||||||
|
|
||||||
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:
|
while a<=b:
|
||||||
mid = (a+b)//2
|
mid = (a+b)//2
|
||||||
if primes[mid]<x:a=mid+1
|
if li[mid]<x:a=mid+1
|
||||||
elif primes[mid]>x: b= mid-1
|
elif li[mid]>x: b= mid-1
|
||||||
else:return True
|
else:return mid
|
||||||
return False
|
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
|
''' mbinary
|
||||||
#########################################################################
|
#########################################################################
|
||||||
# File : tongyu_equation.py
|
# File : modulo_equation.py
|
||||||
# Author: mbinary
|
# Author: mbinary
|
||||||
# Mail: zhuheqin1@gmail.com
|
# Mail: zhuheqin1@gmail.com
|
||||||
# Blog: https://mbinary.coding.me
|
# Blog: https://mbinary.coding.me
|
||||||
# Github: https://github.com/mbinary
|
# Github: https://github.com/mbinary
|
||||||
# Created Time: 2018-10-02 21:14
|
# Created Time: 2018-3-4 21:14
|
||||||
# Description:
|
# 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
|
import re
|
||||||
|
|
||||||
|
from gcd import xgcd
|
||||||
def primeFactoize(x):
|
from euler import phi
|
||||||
'''质因数分解 , ret {p:r}'''
|
from isPrime import isPrime
|
||||||
if isPrime(x):return {x:1}
|
from factor import factor
|
||||||
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))
|
|
||||||
|
|
||||||
def ind(m,g):
|
def ind(m,g):
|
||||||
''' mod m ,primary root g -> {n:indg n}'''
|
''' mod m ,primary root g -> {n:indg n}'''
|
||||||
|
@ -61,22 +25,20 @@ def ind(m,g):
|
||||||
|
|
||||||
def gs(m,num=100):
|
def gs(m,num=100):
|
||||||
'''return list of m's primary roots below num'''
|
'''return list of m's primary roots below num'''
|
||||||
phi = euler(m)
|
p = phi(m)
|
||||||
mp = primeFactoize(phi)
|
mp = factor(p)
|
||||||
checkLst = [phi//i for i in mp]
|
checkLst = [p//i for i in mp]
|
||||||
return [i for i in range(2,num) \
|
return [i for i in range(2,num) if all((i**n-1)%m !=0 for n in checkLst)]
|
||||||
if reduce(and_,[(i**n-1)%m !=0 for n in checkLst])]
|
|
||||||
|
|
||||||
def minG(m):
|
def minG(m):
|
||||||
phi = euler(m)
|
p = phi(m)
|
||||||
mp = primeFactoize(phi)
|
mp = factor(p)
|
||||||
checkLst = [phi//i for i in mp]
|
checkLst = [p//i for i in mp]
|
||||||
i=2
|
i=2
|
||||||
while 1:
|
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
|
i+=1
|
||||||
|
|
||||||
|
|
||||||
class solve:
|
class solve:
|
||||||
def __init__(self,equ=None):
|
def __init__(self,equ=None):
|
||||||
self.linearPat= re.compile(r'\s*(\d+)\s*--\s*(\d+)[\s\(]*mod\s*(\d+)')
|
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))
|
print('equation {equ} has no solution'.format(equ=self.equ))
|
||||||
def error(self):
|
def error(self):
|
||||||
print("Error! The divisor m must be postive integer")
|
print("Error! The divisor m must be postive integer")
|
||||||
|
|
||||||
|
|
||||||
def solveLinear(self,a,b,m):
|
def solveLinear(self,a,b,m):
|
||||||
'''ax--b(mod m): solve linear equation with one unknown
|
'''ax--b(mod m): solve linear equation with one unknown
|
||||||
return ([x1,x2,...],m)
|
return ([x1,x2,...],m)
|
||||||
|
@ -100,7 +60,9 @@ class solve:
|
||||||
return None
|
return None
|
||||||
sol=x*b//g
|
sol=x*b//g
|
||||||
m0 = m//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):
|
def check(self,a,b,m):
|
||||||
if m<=0:
|
if m<=0:
|
||||||
self.error()
|
self.error()
|
||||||
|
@ -109,46 +71,46 @@ class solve:
|
||||||
if b<0:b+= -b//m * m
|
if b<0:b+= -b//m * m
|
||||||
return a,b,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):
|
def solveHigh(self,a,n,b,m):
|
||||||
''' ax^n -- b (mod m) ind_mp is a dict of m's {n: indg n}'''
|
''' ax^n -- b (mod m) ind_mp is a dict of m's {n: indg n}'''
|
||||||
ind_mp = ind(m,minG(m))
|
ind_mp = ind(m,minG(m))
|
||||||
tmp = ind_mp[b] - ind_mp[a]
|
tmp = ind_mp[b] - ind_mp[a]
|
||||||
if tmp < 0:tmp+=m
|
if tmp < 0:tmp+=m
|
||||||
print(n,tmp)
|
sol = self.solveLinear(n,tmp,phi(m))
|
||||||
sol = self.solveLinear(n,tmp,euler(m))
|
|
||||||
re_mp = {j:i for i ,j in ind_mp.items()}
|
re_mp = {j:i for i ,j in ind_mp.items()}
|
||||||
print(sol)
|
sols = [re_mp[i] for i in sol[0]]
|
||||||
return [re_mp[i] for i in sol[0]],m
|
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
|
'''tups is a list of tongyu equation groups, like
|
||||||
[(a1,b1,m1),(a2,b2,m2)...]
|
[(a1,b1,m1),(a2,b2,m2)...]
|
||||||
and, m1,m2... are all primes
|
and, m1,m2... are all primes
|
||||||
'''
|
'''
|
||||||
mp = {}
|
mp = {}
|
||||||
|
print('solving group of equations: ')
|
||||||
for a,b,m in tups:
|
for a,b,m in tups:
|
||||||
|
print('{}x--{}(mod {})'.format(a,b,m))
|
||||||
if m in mp:
|
if m in mp:
|
||||||
if mp[m][0]*b!=mp[m][1]*a:
|
if mp[m][0]*b!=mp[m][1]*a:
|
||||||
self.noSol()
|
self.noSol()
|
||||||
return
|
return
|
||||||
else:mp[m] = (a,b)
|
else:mp[m] = (a,b)
|
||||||
product= reduce(lambda i,j:i*j, mp.keys(), 1)
|
product = 1
|
||||||
sol = 0
|
for i in mp.keys():
|
||||||
|
product *=i
|
||||||
|
sol = [0]
|
||||||
for i in mp:
|
for i in mp:
|
||||||
x = self.solveLinear(product//i*mp[i][0],1,i)
|
xs,m = self.solveLinear(product//i*mp[i][0],1,i)
|
||||||
sol+= x*product//i*mp[i][1]
|
new = []
|
||||||
sol%=m
|
for x in xs:
|
||||||
return ([sol],m)
|
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):
|
def __call__(self):
|
||||||
s=input('输入同余方程,用--代表同于号,形如3--5(mod 7)代表3x模7同余于5')
|
s=input('输入同余方程,用--代表同于号,形如3--5(mod 7)代表3x模7同余于5')
|
||||||
li= self.linearPat.findall(s)
|
li= self.linearPat.findall(s)
|
||||||
|
@ -159,5 +121,7 @@ class solve:
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
solver = solve()
|
solver = solve()
|
||||||
res = solver.solveLinear(3,6,9)
|
res = solver.solveLinear(3,6,9)
|
||||||
print(res)
|
print()
|
||||||
print(solver.solveHigh(1,8,3,11))
|
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
|
d+=1
|
||||||
sm = 0
|
sm = 0
|
||||||
for c in p:
|
for c in p:
|
||||||
if c not in dic:return [-1]
|
if c not in dic:return []
|
||||||
sm = sm*d+dic[c]
|
sm = sm*d+dic[c]
|
||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
|
|
|
@ -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