Given a social network containing n members and a log file containing m timestamps at which times pairs of members formed friendships, design an algorithm to determine the earliest time at which all members are connected (i.e., every member is a friend of a friend of a friend … of a friend).
Assume that the log file is sorted by timestamp and that friendship is an equivalence relation. The running time of your algorithm should be $m\log n$ or better and use extra space proportional to $n$.
_Note: these interview questions are ungraded and purely for your own enrichment. To get a hint, submit a solution._
Solution
使用 Weighted Quick Union,Quick Union + path compression 中的任何一个即可达到题目要求(n members 即有 n 个对象,m timestamps 即有 m 次 union 操作)
for (inti=0; i < M; i++) { intp= StdIn.readInt(); intq= StdIn.readInt(); snc.formFriendShip(p, q); if (snc.isAllConnected()) { StdOut.println("The earliest time is : " + snc.getTimestamps()); break; } } }
}
2. Union-find with specific canonical element
Add a method find() to the union-find data type so that find(i) returns the largest element in the connected component containing i. The operations, union(), connected(), and find() should all take logarithmic time or better.
For example, if one of the connected components is {1, 2, 6, 9}, then the find() method should return 9 for each of the four elements in the connected components.
Solution
给并查集算法添加一个 find(i) 函数,该函数能够返回 i 对象所在的连通分量中的最大值。要求 union(), connected(), and find() 操作最多只能是线性对数的复杂度,所以我们在 Weighted Quick Union,Quick Union + path compression 上任选一例来继续添加一个 find 方法。
注:由于原先实现的 Weighted Quick Union 我们已经实现了一个 find() 方法,故本题内容实现在 findMax() 方法中。
实现思路是额外再维护一个 max[] 数组,其中 max[i] 表示以 i 为根节点的树中最大的值,这样如果要获取 i 所在的连通分量中的最大值,只需要找到 i 的根节点 iRoot,max[iRoot] 即是结果。
for (inti=0; i < M; i++) { intp= StdIn.readInt(); intq= StdIn.readInt(); if (uf.connected(p, q)) { continue; } uf.union(p, q); StdOut.println(p + " " + q); }
StdOut.println();
for (inti=0; i < N; i++) { StdOut.print(uf.findMax(i) + " "); }
} }
3. Successor with delete
Given a set of n integers S = { 0, 1, ... , n-1} and a sequence of requests of the following form:
Remove x from S
Find the _successor_ of x: the smallest y in S such that $y \ge x$.
design a data type so that all operations (except construction) take logarithmic time or better in the worst case.
Solution
这道题最直观的方法也许是创建一个长度为 n 的 boolean 数组 isRemove[],一旦删除了 i,就将 isRemove[i] 设为 true,在询问 x 的后继时,从索引 x 开始往后遍历 isRemove[],一旦遇到 false,即找到后继。但这种方法在 wort case 下寻找后继可能需要 n 的复杂度。
if (!isRemove[x]) { return x; } else { intmax= uf.findMax(x); if (max == isRemove.length - 1) { return -1; } else { return max + 1; } }
}
publicstaticvoidmain(String[] args) { SuccessorWithDeleteswd=newSuccessorWithDelete(10); swd.remove(6); StdOut.println("Successor of 6 is : " + swd.find(6)); swd.remove(5); StdOut.println("Successor of 5 is : " + swd.find(5)); swd.remove(3); StdOut.println("Successor of 3 is : " + swd.find(3)); swd.remove(4); StdOut.println("Successor of 4 is : " + swd.find(4)); swd.remove(7); StdOut.println("Successor of 7 is : " + swd.find(7)); StdOut.println("Successor of 3 is : " + swd.find(3)); StdOut.println("Successor of 2 is : " + swd.find(2)); }