- 博客(192)
- 收藏
- 关注
原创 算法(84):NFA constructor,applications-23.4,23.5
nfa的图构建,主要一点是如何处理or和括号。左括号和or都要入栈,碰到右括号就出栈到左括号,如果遇到or就做特殊处理。括号和or也影响了*的处理,遇到星号,星号代表的重复范围可能会变,有时重复的是单个字符,有时则是一个组,甚至一个正则表达式。
2026-11-07 20:56:57
290
原创 数电:门电路中的PMOS网络与NMOS网络,从电路读表达式。
只有结合这两部你才能读到一个正确的OUT与输入之间的关系,而在pmos网络中,导通就代表着out为1,在nmos网络则相反,这才是为什么pmos网络直接读结构写出来的东西不会错——导通与输出高电平这两件事是一致的,即便我们常常漏看这一点。那么到这里,上面的逻辑已经可以帮我们解释为什么读出的OUT=AB还差了个取反关系了,但“读数的关系”这个理论也是具有漏洞的,那就是它只读出了OUT的电平值和是否导通是一个相反关系,导通了不代表OUT=1,而代表OUT=0。将OUT看作导通,于是写错,漏掉对AB取非的关系。
2026-11-06 21:50:25
171
原创 算法(83):REs and NFAs-23.2
从dfa到nfa,论如何实现regular expression,nfa作为dfs/bfs的变种。其具有两种跳转,一种是ε跳转(瞬间跳转),另一种是有途径的matched跳转。下一状态的维护使用set,这将是一个高效的维护。这是静态的(?),因此不需要维持复杂的并查集存储结构。
2026-11-05 21:01:30
226
原创 算法(82):regular expressions(intro)-23.1
正则表达式Regular expression。这不是说数电的那个正则表达式,而是指把要搜索的patterns抽象成一个正则表达式,写下这个表达式,就是写下无数符合正则算符想表达的patterns。这套东西同样是子串搜索,不一样的是,现在我们可以用一个表达式搜索一堆东西了。
2026-11-05 19:51:23
139
原创 算法(81):Rabin-Karp-22.5
Rabin-Karp也是文本滑动的模式,与pattern等长的子串都被计算成哈希值,并且这种计算类似于队列,当最高有效位离开,哈希值整体向前一位,而后新字符的最低有效位补进来。这个算法之所以快,是因为没有像暴力算法常常回退,每次出去一个字符,又进来一个字符。pattern和子串之间的比较,不是前进又回退的逐字符比较,而是一次整形比较。这样,不仅没有回退的指针跳跃,比较的次数也变少,还能处理多维数据。
2026-10-29 19:50:33
7
原创 算法(80):Boyer-Moore-22.4
boyer-moore的子字符串搜索方法。这种方法有别于KMP的dfa,它主要是滑动pattern而不是滑动文本,dfa则是滑动文本在虚拟的X队列(根据匹配正确或否,定住或继续滑动)。boyer-moore从右向左对 pattern 和文本进行匹配。只要匹配不上 pattern,就向右滑动。向右滑动的情况有三种:第一种:没有重合,直接滑动;第二种:错误处字符重合,将rightmost的相应字符挪到该位置,pattern不左滑;第三种:重合,按照二操作,左滑,则强制pattern右滑一位。
2026-10-29 18:33:18
90
原创 算法(79):Knuth-Morris-Pratt-22.3
关于dfa的构建和其在子串搜索中的运用。DFA 是确定有限自动状态机,它通过最长真前后缀,简化所有可能输入对pattern匹配结果的构建,这种简化依赖于最长真前后缀情况下与前缀情况下的错误等价这一数学规律,这个规律在ppt中没有被提到。dfa最长真前后缀的构建,对应这样的物理过程:字符入队,首个字符略去,后续字符若匹配正确则一直保留,匹配不正确就全部出队。
2026-10-29 15:46:40
296
原创 算法(78):brute force-22.2
讲解brute force暴力算法。暴力算法的执行结构是将每一位字符都作为pattern匹配,那么就需要备份,时间复杂度很高,还会出现指针回滚。因此,这个算法不采用,或者说只有在数据规模小时采用,需要改进。
2026-10-21 18:18:36
167
原创 算法(77):substringSearch intro-22.0
substringSearch的intro。这一章的主要内容是讲如何在长文本中找到一个远比文本长度小的子串,intro介绍了几种要学到的方式。
2026-10-19 22:30:01
204
原创 算法(76):character-based operations-21.3
基于tries的字符级别操作。可以做到的有,前缀匹配、查找最长公共前缀,T9输入法,基于后缀数组的查找等。同时,还有一些tries的变种,例如可以禁止单字符串结构的变种,用于节省空间。总之,tries由于存储的数据既是字符又是数字的特性,发展出了有别于红黑树和各类数组的存储方式。
2026-10-19 22:23:06
175
原创 算法(75):拾遗,TST with R2 branching at root-21.2
为ternary search tree做起步加速,方法是前两层也就是前两个字母的节点存储使用r方-way tries。如果单词是单字母单词则将单词看作 字符+特殊字符/0,如果但此时双字母单词则直接将val存储在r方tries的节点val上。这样加速了起步,却没有多用很多空间,是一个较好的选择。
2026-10-19 17:47:44
336
原创 算法(74):ternary search tries-21.2
ternary search tries是对r way tries的改进,具体来说是限制了一个节点下能连接子节点的数量。在tst中,一个节点只能连接三个子节点,其中该节点的左右子节点和该节点实为同级,只有其中间子节点属于下一个字符的比较范畴。ternary search tries通过这样的结构,维持了使用空间与红黑树持平,比哈希表小,速度比红黑树快,比哈希表略快,尤其是在不命中的时候。因此,ternary search tries成为字符串查找比较的最优选择。
2026-10-15 21:04:32
110
原创 算法(73):R-way Tries-21.1
R-way tries,每个节点下除了包括一个Object类型的value(被取出时会被强制转化回Value类型),还有一个Radix大小的子节点数组。查找的可能是hit和miss,hit是一路都有内容的子节点,最后能返回一个值;miss是遇到null节点,或节点有内容却没有值。之所以使用Object value,是因为static private类无法读取外部类型,因此也无法泛型。特别注意的一点,建立r-way tries时如果写入重复值,会被覆盖。由于这个方法查找快但用的空间太大,还需要改进!
2026-10-13 20:48:41
170
原创 算法(72):Tries intro(retrieval-检索)
tries来自retieval而不是try,该方法的提出是为了应对字符串的查找。字符串无论是使用红黑树存储,还是哈希表,都可能得遍历大量重复前缀,因为需要将字符串几乎整个比较完。tries提出了一种由值和子节点数组构成的节点结构,再由这些节点构成树。每次经过节点无需全部比较,而是比较单个字符,如果遇到null则证明不存在。这个方法提高了速度,却使用了大量空间。
2026-10-13 17:07:04
325
原创 算法(70):suffix arrays(上:背景介绍)
suffix arrays主要讲利用keyword in context search在长文本中进行快速查找匹配。如果使用传统法,每次进行查找都要从头开始扫描,时间很长;而使用kwic方法,对文本构建后缀数组,并按字典序排序,进行预处理简化查找匹配。在kwic中的quicksort不能继续发挥缓存友好的优势,因为后缀数组实际上是指向同一段文本来源的引用,只是,我们对这些后缀引用进行了索引排序。因此,我们实际上排序的既不是引用,也不是字符或字符串,而是整形数字;也由此,我们失去了缓存友好的特性,跳转太大了
2026-10-12 17:29:19
181
原创 算法(69):3-way radix quicksort
3way string quicksort是一种结合了quicksort和MSD的方法,它使用quicksort,对于字符串进行基于标杆数的比较,而后进行原地排序,缓存友好。它结合MSD radix sort,因此不用每次重复比较重叠的前缀,节省了算法运行时间。这个算法要注意的地方有两个,一是指针的运动,要了解这一点,就要清晰lt、i、gt的含义;另一个是注意每次比较都是基于radix的比较,因此if v<0这个条件就是sort的跳过条件,因为符合该条件的字符串组一定已经全部截止了。
2026-10-08 17:18:13
364
原创 算法(68):key-indexed counting,MSD radix sorting.specail point-19.2~4
key-indexed counting方法对字符串进行排序,是通过创建一个编码个数大小的数组,而后数出每种编码的个数(要按列看,这里的编码就是每个字符串中的同列字符),再通过每种个数数出累计个数,以累积数来确定这些字符串的相对排序。MSD radix sort和LSD都使用了KIC方法,不同的是MSD还有递归。MSD递归的指针变化方式类似于快速排序,是在同组中进入更小组的方法。当每组字符串过少,MSD就变得非常慢(因为同样需要编码格式大小的count数组),所以一组数量少时用插入排序代替
2026-10-06 17:16:36
326
原创 算法(67):String in java/INTRO-20.1
这一节主要是讲解为什么要设计有关string的算法,以及string的两种实现。字符串无处不在,所以对它进行的操作有查找对比,在长文中筛选等,设计对于它的算法十分必要。字符串的结构有两种,一种是mutable的,另外一种是immutable的。由于他们可修改和不可修改的特性,对其进行的操作的时间复杂度和额外空间都不同。对可修改的字符串,提取其中的一些内容,必须重新开辟一片空间,再把提取的内容放进去,这是为了不让提取出来的内容随着原字符串的修改而改变。对不可改的,则可以直接将指针指向原字符串
2026-10-04 21:41:53
345
原创 c++学习(18):多线程基础
多线程在c++中的运行是我们创建多个独立运行的线程,在其中运行不同的东西。其中,要注意的一点是,对于线程可能需要阻塞,否则或会出现线程还没运行完,程序就结束了的情况,会报错。
2026-10-03 17:32:12
184
原创 算法(65):maxflow-mincut theorem-19.3
概念:流:一种分配方案,由于这会导致特定的流出s/流入t,所以可以以二者来衡量流。流的值:流出s和流入t的值,它们是同一个。割:一种把点分成不同set的方式,这里是只能分成两个set,并且s和t不在同一set的st cut割容量:A set到B set的所有正向容量。净流:割中正向减去负向的流量。流=割:指的是流值在数值上与割容量相等。最大流-最小割定理:任何流值必然≤任何割容量,因为从A set到B set的流值就是总值,故割容量能容纳流。因此若有流值=割值,必然是最大流,也是最小割。
2026-09-29 18:39:00
344
原创 算法(64):augmenting path-19.2
augmenting path是一个Max Flow的特别概念,其在把图中每条边都看成双向边的残余网络做规划。残余网络:把每条边都看成两条边,正向看剩余容量,用于加容量;反向看流,用于减流量。我们规划增广路径的时候,可以对前面的路径走局部反向,走反向边其实就是撤销之前分配的流量。只有先分配了,才可以撤销。并不是说,真的存在一条反向边,而是这是在最优流量规划中的一种计算方式,确切地说是用于“后悔”。
2026-09-27 11:55:32
293
原创 算法(63):Maxflow intro-19.1
最大流问题作为一种带权图问题的基本概念介绍。容量:带权图的权值设定为正的double类型,作为容量。流:一种对edge的赋值,在0和容量之间,是一种赋值。最大流问题:找出从s到t的最大流,跟找出容量最大的cut是同一个问题。
2026-09-27 11:05:59
344
原创 算法(62):Bellford algorithm的证明,negative weights-18.5
bellman-ford算法具有严格的证明,其证明使用了数学归纳法。外层循环每进行一轮,路径所位于的局部最短路径上限涵盖的边就多一。直到,我们将所有边都涵盖进来,会获得全局最短路径。
2026-09-25 19:03:10
316
原创 算法(61):Dijsktra算法中的decrease key操作-18.3
关于Shortest Path的Dijkstra算法时间复杂度问题。由于其程序/算法是,对于每层的点逐一进行松弛,因此对PQ的操作是对于点的操作,所以插入和删除操作的数量级都是V,而decrease key操作通过qp数组,把找到的更短edge weight权重放入PQ,是对于E的操作,最差情况是E。比较有意思的一点,Dijkstra算法和prim算法的eager版本,都是使用可decrease key的pq避免膨胀,使用它的关键是要维护一个qp数组,以此替代在binary heap中的搜索。
2026-09-23 18:15:51
54
原创 算法(60):Prim’s algorithm is essentially the same algorithm-18.3
说Prim’s algorithm is essentially the same algorithm,是因为它们共享同一个算法骨架,而不是说prim的算法可以用于计算shortest path,它不能。它计算的是最小mst,不看累计,而是看单边,并且这种算法源于cut和crossing edge那一页的证明。
2026-09-23 12:02:46
189
1
原创 算法(58):Shortest Path算法的证明-18.1~18.3
SP算法的正确性证明。一个路径是SP需要符合三个条件:①distTo[s]=0;②PathTo[v]是s->v的某条路径,distTo[v]是对应的路径权重;③distTo[v]<distTo[v k-1]+e k。当我们证明必要性,证明的是符合条件三的是SP,用反证法证明不符合条件三则不是SP;当我们证明充分性,证明符合三条件的是SP,把不等式按照条件三依次展开,而后又由于条件二,distTo等于最短路径权重。证明了SP循迹的正确性。
2026-09-21 11:37:44
181
原创 算法(56): Prim‘s algorithm-17.5
prim s algorithm,有lazy版本和eager版本。lazy版本维护一个edge类型的PQ,将有一个end point in T的边维护在里面,如果这些边后续变成两个点都在T中,也不马上做处理,而是顺序弹出的时候才消失,因此可能导致占用空间上升到E。Eager版本维护的对象是与T中点同处一边的点,每个点附带最小权值边。每次更新T后可能导致PQ中点所带的权值变更,并且只可能减小,所以在PQ里面swim就可以,这里要注意维护pq和qp。以及kruskal算法其实不讲cut,每次就是加最小边
2026-09-08 21:35:16
242
原创 算法(55):Kruskal‘s Algorithm的时间复杂度问题-17.4
minimum spanning tree生成过程中的连通性查询问题,比较几种算法的时间复杂度,发现依旧是union-find为最佳策略。
2026-09-07 17:01:08
335
原创 算法(54):MST,greedy algorithm-17.1,17.2
minimum spanning tree,MST最小生成树的介绍和定义。MST生成于带权cc,却既没有环,又以最小代价连通所有顶点。生成MST的算法是greedy algorithm,算法建立在cut和crossing edge的基础上。cut是一个动作,把cc中的所有顶点分为两个set,s和V-s;而crossing edge则把这两个set连接起来。greedy algorithm中,每次把G分为2 sets,而后选取权重最小的crossing edge,直到有V-1条边。
2026-09-06 17:44:05
156
原创 算法(52):从topological sort到cycle detection
topological sort(暂称TS)与Directed cycle detection application之间的关系。由于TS的对象必须是directed acyclic graph,所以在做TS之前必须进行一个环检测。环检测的代码与TS在结构和内容上都非常相似,仅仅是在TS上另外维护了数组和栈。对于访问过的顶点,如果还未返回,我们就标记onStack为true,如果后续再次访问到该顶点就能有所察觉,判断有环。而在这个情况下再把沿途顶点都放入栈中,就可以获得在环中的顶点。
2026-09-04 17:53:34
379
2
原创 算法(51):topological-16.4
拓扑学研究的是一个东西在连续变形下保持不变的性质。偏序指的是在一个set中的元素部分有序,全序就是全部有序。topological sort就是把偏序整理好,并插入不能排序的元素形成全序。
2026-09-03 19:07:06
325
原创 算法(50): intro,API-16.1,16.2
digraph是directed graph的缩写,无向图可以看作digraph的特例。digraph使用的也是vertex indexed array of list,这使得sparse bigraph具有一个有效的存储形式,也使基于这个数据结构的算法复杂度从list of edges的E进化到仅仅是V节点的outdegree
2026-09-02 18:17:20
210
1
原创 算法(48):Union Find-2.0(以及review)
unionFind主要维护的是一个动态的连通性问题。所谓动态连通性就是,查询连通性前后还可能有对于集内元素的插入/删除操作。图的遍历算法之所以不使用unionFind查询连通性是因为图建立的事静态连通集。算法前半部课的脉络是静态数据集(数组)sort方法,动态数据集(链表)/键值对ST方法,其中还有抽象数据类型栈堆包。
2026-09-01 17:31:08
296
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅