Skip to content

Commit 8ac95fd

Browse files
author
liaomingtian
committed
🦄 refactor(monge):
1 parent 0b8f446 commit 8ac95fd

File tree

78 files changed

+271
-1198
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+271
-1198
lines changed

11_动态规划/dp优化/AlienDp(wqs二分)/AliensDp.ts renamed to 11_动态规划/dp优化/四边形不等式Monge优化dp/monge/AlienDp(wqs二分)/AliensDp.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@
1010
* @see
1111
* https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/solution/yi-chong-ji-yu-wqs-er-fen-de-you-xiu-zuo-x36r/
1212
*/
13-
function aliensDp(
14-
k: number,
15-
getDp: (penalty: number) => [best: number, maxOperation: number]
16-
): number {
13+
function aliensDp(k: number, getDp: (penalty: number) => [best: number, maxOperation: number]): number {
1714
let left = 1
1815
let right = 2e15
1916
let penalty = 0
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,37 @@
11
https://kmyk.github.io/monotone-matrix-visualizer/
2-
2+
https://topcoder-g-hatena-ne-jp.jag-icpc.org/spaghetti_source/20120915/1347668163.html
33
https://maspypy.github.io/library/convex/monge.hpp
44

55
[monge グラフ上の d-辺最短路の d=1,...,N における列挙](https://nyaannyaan.github.io/library/dp/monge-d-edge-shortest-path-enumerate.hpp)
66
[monge グラフ上の d-辺最短路](https://nyaannyaan.github.io/library/dp/monge-d-edge-shortest-path.hpp)
77
[monge グラフ上の最短路](https://nyaannyaan.github.io/library/dp/monge-shortest-path.hpp)
88
[monotone minima](https://nyaannyaan.github.io/library/dp/monotone-minima.hpp)
9+
10+
---
11+
12+
Monge 图:
13+
14+
```
15+
给定一个n个顶点的DAG,图中的每个顶点i都有一条边指向编号j(i<j),且边的权重满足Monge性质(也就是四边形不等式),dist(a, b) + dist(c, d) ≤ dist(a, d) + dist(c, b),这个图就是Monge图
16+
```
17+
18+
---
19+
20+
- **SMAWK(totally monotone minima; TM minima)**:
21+
`O(ROW+COL)` 时间复杂度求出一个全单调矩阵的每行的最小值
22+
- **Monotone Minima**:
23+
`O(ROW+COL*logROW)` 时间复杂度求出一个单调矩阵的每行的最小值
24+
- **Monge**:
25+
`O(nlogmax)`求出 Monge 图的 d 边最短路
26+
27+
---
28+
29+
## Totally Monotone 和 Monotone 有什么区别?
30+
31+
"Monotone"(单调)和"Totally Monotone"(全单调)是两种不同的数学性质,它们都可以用来描述函数或矩阵。
32+
33+
1. "Monotone"(单调):通常用来描述一个函数或序列,如果它的值随着输入的增加而单调增加或单调减少,那么我们就说这个函数或序列是单调的。例如,函数 f(x) = x^2 在 x >= 0 时就是单调的,因为当 x 增加时,f(x)的值也增加。
34+
35+
2. "Totally Monotone"(全单调):是一种更强的单调性质,通常用来描述矩阵或二元函数。对于一个矩阵或函数,如果它满足对于任意的 i < j 和 k < l,如果矩阵的[i][k]元素大于矩阵的[j][l]元素,那么矩阵的[i][l]元素也大于矩阵的[j][k]元素,那么我们就说这个矩阵或函数是全单调的。
36+
37+
总的来说,全单调是一种更强的单调性质,它要求函数或矩阵在多个维度上都保持单调性。而单调只要求函数或序列在一个维度上保持单调性。

17_模式匹配/AC自动机(多模式匹配)/acwing1285.单词.py

-18
This file was deleted.

17_模式匹配/AC自动机(多模式匹配)/2781. 最长合法子字符串的长度-AC自动机-MLE.ts renamed to 17_模式匹配/AC自动机(多模式匹配)/legacy/2781. 最长合法子字符串的长度-AC自动机-MLE.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { DefaultDict } from '../../5_map/DefaultDict'
2-
import { ACAutoMaton } from './ACAutoMaton'
1+
import { DefaultDict } from '../../../5_map/DefaultDict'
2+
import { ACAutoMatonLegacy } from './ACAutoMatonLegacy'
33

44
// !因为字符串总长度太大(1e6),MLE了
55
const INF = 2e15
66
function longestValidSubstring(word: string, forbidden: string[]): number {
7-
const acm = new ACAutoMaton()
7+
const acm = new ACAutoMatonLegacy()
88
const minLen = new DefaultDict(() => INF)
99
forbidden.forEach((pattern, id) => {
1010
acm.insert(id, pattern, pos => {

17_模式匹配/AC自动机(多模式匹配)/2781. 最长合法子字符串的长度-AC自动机.py renamed to 17_模式匹配/AC自动机(多模式匹配)/legacy/2781. 最长合法子字符串的长度-AC自动机.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from collections import defaultdict
2121
from typing import List
22-
from ACAutoMaton import ACAutoMaton
22+
from ACAutoMatonLegacy import ACAutoMatonLegacy
2323

2424
INF = int(1e18)
2525

@@ -33,7 +33,7 @@ def dp(pre: int, cur: int) -> None:
3333
minLen[cur] = min(minLen[cur], minLen[pre])
3434

3535
minLen = defaultdict(lambda: INF) # !ac自动机每个状态匹配到的模式串的最小长度
36-
acm = ACAutoMaton()
36+
acm = ACAutoMatonLegacy()
3737
for i, s in enumerate(forbidden):
3838
acm.insert(i, s, didInsert=didInsert)
3939
acm.build(dp=dp)

17_模式匹配/AC自动机(多模式匹配)/ACAutoMatonArray.go renamed to 17_模式匹配/AC自动机(多模式匹配)/legacy/ACAutoMatonArrayLegacy.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// !Trie由数组实现,比map实现的Trie快很多.
44
//
55
// API
6-
// Insert(id int, s string, didInsert func(pos int)) *ACAutoMatonArray
6+
// Insert(id int, s string, didInsert func(pos int)) *ACAutoMatonArrayLegacy
77
// Build(heavy bool, dp func(fail, next int))
88
// Match(state int, s string) map[int][]int
99
// Move(pos, char) int
@@ -18,12 +18,12 @@ package main
1818
// https://leetcode.cn/problems/stream-of-characters/
1919

2020
type StreamChecker struct {
21-
acm *ACAutoMatonArray
21+
acm *ACAutoMatonArrayLegacy
2222
state int
2323
}
2424

2525
func Constructor(words []string) StreamChecker {
26-
acm := NewACAutoMatonArray()
26+
acm := NewACAutoMatonArrayLegacy()
2727
for i, word := range words {
2828
acm.Insert(i, word, nil)
2929
}
@@ -44,22 +44,22 @@ const (
4444
_MARGIN byte = 'a' // 字符集起始字符
4545
)
4646

47-
type ACAutoMatonArray struct {
47+
type ACAutoMatonArrayLegacy struct {
4848
*Trie // !继承自Trie
4949
count []int
5050
heavy bool
5151
}
5252

53-
func NewACAutoMatonArray() *ACAutoMatonArray {
54-
res := &ACAutoMatonArray{Trie: _newTrie()}
53+
func NewACAutoMatonArrayLegacy() *ACAutoMatonArrayLegacy {
54+
res := &ACAutoMatonArrayLegacy{Trie: _newTrie()}
5555
return res
5656
}
5757

5858
// bfs为字典树的每个结点添加失配指针,结点要跳转到哪里.
5959
//
6060
// heavy: 是否处理出每个结点匹配到的模式串id.
6161
// dp: AC自动机构建过程中的回调函数,入参为`(next结点的fail指针, next结点)`.
62-
func (ac *ACAutoMatonArray) Build(heavy bool, dp func(fail, next int)) {
62+
func (ac *ACAutoMatonArrayLegacy) Build(heavy bool, dp func(fail, next int)) {
6363
ac.count = make([]int, len(ac.states))
6464
for i, v := range ac.states {
6565
ac.count[i] = len(v.matching)
@@ -111,7 +111,7 @@ func (ac *ACAutoMatonArray) Build(heavy bool, dp func(fail, next int)) {
111111
// state : ac自动机的状态.根节点状态为0.
112112
// s : 待匹配的字符串.
113113
// 返回每个模式串在`s`中出现的下标.
114-
func (ac *ACAutoMatonArray) Match(state int, s string) map[int][]int {
114+
func (ac *ACAutoMatonArrayLegacy) Match(state int, s string) map[int][]int {
115115
if !ac.heavy {
116116
panic("需要调用build(heavy=True)构建AC自动机")
117117
}
@@ -127,12 +127,12 @@ func (ac *ACAutoMatonArray) Match(state int, s string) map[int][]int {
127127
}
128128

129129
// 当前节点匹配的完整的模式串的个数.
130-
func (ac *ACAutoMatonArray) Count(pos int) int {
130+
func (ac *ACAutoMatonArrayLegacy) Count(pos int) int {
131131
return ac.count[pos]
132132
}
133133

134134
// 当前节点状态是否为可接受(后缀匹配到了模式串).
135-
func (ac *ACAutoMatonArray) Accept(pos int) bool {
135+
func (ac *ACAutoMatonArrayLegacy) Accept(pos int) bool {
136136
return ac.count[pos] > 0
137137
}
138138

17_模式匹配/AC自动机(多模式匹配)/_ACAutoMatonArray.ts renamed to 17_模式匹配/AC自动机(多模式匹配)/legacy/ACAutoMatonArrayLegacy.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
/**
55
* @deprecated
66
*/
7-
class ACAutoMatonArray {
7+
class ACAutoMatonArrayLegacy {
88
/**
99
* 模式串列表.
1010
*/
@@ -177,16 +177,16 @@ class ACAutoMatonArray {
177177
}
178178
}
179179

180-
export { ACAutoMatonArray }
180+
export { ACAutoMatonArrayLegacy }
181181

182182
if (require.main === module) {
183183
// 1032. 字符流
184184
// https://leetcode.cn/problems/stream-of-characters/
185185
class StreamChecker {
186-
private readonly _acm: ACAutoMatonArray
186+
private readonly _acm: ACAutoMatonArrayLegacy
187187
private _state = 0
188188
constructor(words: string[]) {
189-
this._acm = new ACAutoMatonArray()
189+
this._acm = new ACAutoMatonArrayLegacy()
190190
words.forEach((word, i) => this._acm.insert(i, word))
191191
this._acm.build()
192192
}
@@ -206,7 +206,7 @@ if (require.main === module) {
206206
// 面试题 17.17. 多次搜索
207207
// https://leetcode.cn/problems/multi-search-lcci/
208208
function multiSearch(big: string, smalls: string[]): number[][] {
209-
const acm = new ACAutoMatonArray()
209+
const acm = new ACAutoMatonArrayLegacy()
210210
smalls.forEach((small, i) => acm.insert(i, small))
211211
acm.build(true)
212212

17_模式匹配/AC自动机(多模式匹配)/ACAutoMaton.go renamed to 17_模式匹配/AC自动机(多模式匹配)/legacy/ACAutoMatonLegacy.go

+13-13
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ package main
77
// https://leetcode.cn/problems/stream-of-characters/
88

99
type StreamChecker struct {
10-
acm *ACAutoMaton
10+
acm *ACAutoMatonLegacy
1111
state int
1212
}
1313

1414
func Constructor(words []string) StreamChecker {
15-
acm := NewACAutoMaton()
15+
acm := NewACAutoMatonLegacy()
1616
for i, word := range words {
1717
acm.Insert(i, word, nil)
1818
}
@@ -32,7 +32,7 @@ func (this *StreamChecker) Query(letter byte) bool {
3232
// 面试题 17.17. 多次搜索
3333
// https://leetcode.cn/problems/multi-search-lcci/
3434
func multiSearch(big string, smalls []string) [][]int {
35-
acm := NewACAutoMaton()
35+
acm := NewACAutoMatonLegacy()
3636
for i, word := range smalls {
3737
acm.Insert(i, word, nil)
3838
}
@@ -54,7 +54,7 @@ func multiSearch(big string, smalls []string) [][]int {
5454
// https://leetcode.cn/problems/length-of-the-longest-valid-substring/
5555
func longestValidSubstring(word string, forbidden []string) int {
5656
const INF int = 1e18
57-
acm := NewACAutoMaton()
57+
acm := NewACAutoMatonLegacy()
5858
minLen := make(map[int]int)
5959

6060
for i, word := range forbidden {
@@ -106,7 +106,7 @@ func max(a, b int) int {
106106

107107
//###############################################################
108108

109-
type ACAutoMaton struct {
109+
type ACAutoMatonLegacy struct {
110110
patterns []string // 模式串列表
111111
children []map[byte]int // trie树,children[i]表示节点(状态)i的所有子节点,0表示虚拟根节点
112112
wordCount []int // trie树结点附带的信息.count[i]表示节点(状态)i的匹配个数
@@ -115,8 +115,8 @@ type ACAutoMaton struct {
115115
heavy bool // 构建时是否在matching中处理出每个结点匹配到的模式串id
116116
}
117117

118-
func NewACAutoMaton() *ACAutoMaton {
119-
res := &ACAutoMaton{}
118+
func NewACAutoMatonLegacy() *ACAutoMatonLegacy {
119+
res := &ACAutoMatonLegacy{}
120120
res.children = append(res.children, make(map[byte]int))
121121
res.matching = append(res.matching, make([]int, 0))
122122
return res
@@ -127,7 +127,7 @@ func NewACAutoMaton() *ACAutoMaton {
127127
// pid : 模式串的唯一标识id.
128128
// pattern : 模式串.
129129
// didInsert : 模式串插入后的回调函数,入参为结束字符所在的结点(状态).
130-
func (acm *ACAutoMaton) Insert(pid int, pattern string, didInsert func(state int)) *ACAutoMaton {
130+
func (acm *ACAutoMatonLegacy) Insert(pid int, pattern string, didInsert func(state int)) *ACAutoMatonLegacy {
131131
if len(pattern) == 0 {
132132
return acm
133133
}
@@ -159,7 +159,7 @@ func (acm *ACAutoMaton) Insert(pid int, pattern string, didInsert func(state int
159159
//
160160
// heavy : 是否处理出每个结点匹配到的模式串id.
161161
// dp : AC自动机构建过程中的回调函数,入参为`(next结点的fail指针, next结点)`.
162-
func (acm *ACAutoMaton) Build(heavy bool, dp func(move, next int)) {
162+
func (acm *ACAutoMatonLegacy) Build(heavy bool, dp func(move, next int)) {
163163
acm.wordCount = make([]int, len(acm.children))
164164
for i := 0; i < len(acm.children); i++ {
165165
acm.wordCount[i] = len(acm.matching[i])
@@ -193,7 +193,7 @@ func (acm *ACAutoMaton) Build(heavy bool, dp func(move, next int)) {
193193

194194
// 从当前状态`state`沿着字符`input`转移到的下一个状态.
195195
// 沿着失配链上跳,找到第一个可由char转移的节点.
196-
func (acm *ACAutoMaton) Move(state int, input byte) int {
196+
func (acm *ACAutoMatonLegacy) Move(state int, input byte) int {
197197
for {
198198
nexts := acm.children[state]
199199
if _, ok := nexts[input]; ok {
@@ -211,7 +211,7 @@ func (acm *ACAutoMaton) Move(state int, input byte) int {
211211
// state : ac自动机的状态.根节点状态为0.
212212
// s : 待匹配的字符串.
213213
// 返回每个模式串在`s`中出现的下标.
214-
func (acm *ACAutoMaton) Match(state int, s string) map[int][]int {
214+
func (acm *ACAutoMatonLegacy) Match(state int, s string) map[int][]int {
215215
if !acm.heavy {
216216
panic("需要调用build(heavy=True)构建AC自动机")
217217
}
@@ -227,11 +227,11 @@ func (acm *ACAutoMaton) Match(state int, s string) map[int][]int {
227227
}
228228

229229
// 当前状态`state`匹配到的模式串个数.
230-
func (acm *ACAutoMaton) Count(state int) int {
230+
func (acm *ACAutoMatonLegacy) Count(state int) int {
231231
return acm.wordCount[state]
232232
}
233233

234234
// 当前状态`state`是否为匹配状态.
235-
func (acm *ACAutoMaton) Accept(state int) bool {
235+
func (acm *ACAutoMatonLegacy) Accept(state int) bool {
236236
return acm.wordCount[state] > 0
237237
}

17_模式匹配/AC自动机(多模式匹配)/ACAutoMaton.py renamed to 17_模式匹配/AC自动机(多模式匹配)/legacy/ACAutoMatonLegacy.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from typing import Callable, DefaultDict, List, Optional
1212

1313

14-
class ACAutoMaton:
14+
class ACAutoMatonLegacy:
1515
"""AC自动机,多模式串匹配."""
1616

1717
__slots__ = ("_patterns", "_children", "_wordCount", "_matching", "_fail", "_heavy")
@@ -37,7 +37,7 @@ def __init__(self):
3737

3838
def insert(
3939
self, pid: int, pattern: str, didInsert: Optional[Callable[[int], None]] = None
40-
) -> "ACAutoMaton":
40+
) -> "ACAutoMatonLegacy":
4141
"""将模式串`pattern`插入到Trie树中.模式串一般是`被禁用的单词`.
4242
4343
Args:
@@ -146,7 +146,7 @@ def accept(self, pos: int) -> bool:
146146
if __name__ == "__main__":
147147

148148
def demo() -> None:
149-
ac = ACAutoMaton()
149+
ac = ACAutoMatonLegacy()
150150
ac.insert(0, "he")
151151
ac.insert(1, "she")
152152
ac.insert(2, "his")
@@ -168,7 +168,7 @@ def demo() -> None:
168168
class Solution:
169169
def multiSearch(self, big: str, smalls: List[str]) -> List[List[int]]:
170170
"""多模式匹配indexOfAll"""
171-
ac = ACAutoMaton()
171+
ac = ACAutoMatonLegacy()
172172
for i, small in enumerate(smalls):
173173
ac.insert(i, small)
174174
ac.build(heavy=True)
@@ -186,7 +186,7 @@ def multiSearch(self, big: str, smalls: List[str]) -> List[List[int]]:
186186
# https://leetcode.cn/problems/stream-of-characters/
187187
class StreamChecker:
188188
def __init__(self, words: List[str]):
189-
self._ac = ACAutoMaton()
189+
self._ac = ACAutoMatonLegacy()
190190
for i, word in enumerate(words):
191191
self._ac.insert(i, word)
192192
self._ac.build()

0 commit comments

Comments
 (0)