String similarity
如何衡量两个字符串的相似度?
引入edit distance的概念
δ
+
α
p
,
q
\delta + \alpha_{p,q}
δ+αp,q gap+mismatch 即,
填充一个空格或者把pq对应位置的字母换成一致,最终使得两个字符串达到一致
需要最小化这个距离
Hirschberg算法可将空间压缩到 θ ( m + n ) \theta(m+n) θ(m+n)
单汇最短路径
【这里复习一下dijkstra算法 贪心在图中的应用】
当有负边的时候,dijkstra不管用了
Bellman Ford算法 解决图中有负边的最短路径问题
注意:里面两层for循环加起来的时间复杂度是
θ
(
m
)
\theta(m)
θ(m)
总的时间复杂度是
θ
(
n
m
)
\theta(nm)
θ(nm)
画出依赖关系图可知,每行只依赖于前一行,空间压缩可以将i这一维压缩
用d(v)目前表示v~t的最短路径大小
点的遍历顺序不重要,若d(w)上一轮没有更新,则在下一轮也不用更新了,所有的d(v)都不变,整个算法终止。
在循环i次时,d(v)是v~t用i条边到达的一个下界,
若循环到n轮,仍有值发生改变,说明有负环。
// The main function that finds shortest distances from src to
// all other vertices using Bellman-Ford algorithm. The function
// also detects negative weight cycle
void BellmanFord(struct Graph* graph, int src)
{
int V = graph->V;
int E = graph->E;
int dist[V];
// Step 1: Initialize distances from src to all other vertices
// as INFINITE
for (int i = 0; i < V; i++)
dist[i] = INT_MAX;
dist[src] = 0;
// Step 2: Relax all edges |V| - 1 times. A simple shortest
// path from src to any other vertex can have at-most |V| - 1
// edges
for (int i = 1; i <= V-1; i++)
{
for (int j = 0; j < E; j++)
{
int u = graph->edge[j].src;
int v = graph->edge[j].dest;
int weight = graph->edge[j].weight;
if (dist[u] != INT_MAX && dist[u] + weight < dist[v])
dist[v] = dist[u] + weight;
}
}
// Step 3: check for negative-weight cycles. The above step
// guarantees shortest distances if graph doesn't contain
// negative weight cycle. If we get a shorter path, then there
// is a cycle.
for (int i = 0; i < E; i++)
{
int u = graph->edge[i].src;
int v = graph->edge[i].dest;
int weight = graph->edge[i].weight;
if (dist[u] != INT_MAX && dist[u] + weight < dist[v])
printf("Graph contains negative weight cycle");
}
printArr(dist, V);
return;
}
负环检测
使用Bellman Ford算法进行检测,在第n轮更新时有OPT(n,v)改变,则有负环(负环路径上的点的值不一定改变,但是一定会有一个改变的)
Shortest Path Fast Algo (SPFA) Bellman Ford的队列实现
算法大致流程是用一个队列来进行维护。 初始时将源加入队列。 每次从队列中取出一个元素,并对所有与他相邻的点进行松弛,若某个相邻的点松弛成功,则将其入队。 直到队列为空时算法结束。
使用一个队列,每次将顶点前继节点加入队列,队列中的点的值要进行更新
一个点在将要加入队列时,可能已经在队列中,要防止加入队列两次
检测负环:一个点进入队列n次,则有负环
const int INF = 999999;
int map[MAXN][MAXN]; //map[i,j]为初始输入的i到j的距离,未知的map[i,j]=INF;
int dis[MAXN];
char vst[MAXN];
// 参数n表示结点数,s表示源点
int SPFA(int n, int s)
{
// pri是队列头结点,end是队列尾结点
int i, pri, end, p, t;
memset(vst, 0, sizeof(vst));
for(int i=0; i<MAXN; ++i)
Q[i] = 0;
for (i=0; i<n; i++)
dis[i] = INF;
dis[s] = 0;
vst[s] = 1;
Q[0] = s; pri = 0; end = 1;
while (pri < end)
{
p = Q[pri];
for (i=0; i<n; ++i)
{
//更新dis
if (dis[p]+map[p][i] < dis[i])
{
dis[i] = dis[p]+map[p][i];
if (!vst[i]) //未在队列中
{
Q[end++] = i;
vst[i] = 1;
}
}
}
vst[p] = 0; // 置出队的点为未标记
pri++;
}
return 1;
}
LeetCode 练习
Cheapest flights within k stops
Network delay time