- Maximum Association Set
Amazon sells books, every book has books which are strongly associated with it. Given ListA and ListB,indicates that ListA [i] is associated with ListB [i] which represents the book and associated books. Output the largest set associated with each other(output in any sort). You can assume that there is only one of the largest set.
Example
Example 1:
Input: ListA = [“abc”,“abc”,“abc”], ListB = [“bcd”,“acd”,“def”]
Output: [“abc”,“acd”,“bcd”,“def”]
Explanation:
abc is associated with bcd, acd, dfe, so the largest set is the set of all books
Example 2:
Input: ListA = [“a”,“b”,“d”,“e”,“f”], ListB = [“b”,“c”,“e”,“g”,“g”]
Output: [“d”,“e”,“f”,“g”]
Explanation:
The current set are [a, b, c] and [d, e, g, f], then the largest set is [d, e, g, f]
Notice
The number of books does not exceed 5000.
解法1:并查集
首先把A和B中的每本书按globalId编号。
然后union find,最后查每本书的find(x),找出某个祖宗其拥有最多本书。
注意:
1)并查集使用的关键之处就是搞清楚什么时候用father[x],什么时候用find(x)。
find(x)的返回值就是x当前情况下的最高祖宗,在find(x)的过程中,最后father[x]也指向了其当前情况下的最高祖宗。
在merge()过程结束后,可能仍有某些书的father没有指向真正的最高祖宗。所以在接下来的循环中,
for (int i = 0; i < globalIdMax; ++i) {
int fx = find(i); //not father[i]!
在find(x)中,father[x]已经指向其最高祖宗了。
所以在接下来的匹配maxId中,用father[i]而不是find(i)就可以了。
for (int i = 0; i < globalIdMax; ++i) {
if (father[i] == maxId) {
res.push_back(id2Book[i]);
}
}
代码如下:
class Solution {
public:
/**
* @param ListA: The relation between ListB's books
* @param ListB: The relation between ListA's books
* @return: The answer
*/
vector<string> maximumAssociationSet(vector<string> &ListA, vector<string> &ListB) {
int n = ListA.size();
for (int i = 0; i < n; ++i) {
if (book2Id.find(ListA[i]) == book2Id.end()) {
book2Id[ListA[i]] = globalId;
id2Book[globalId] = ListA[i];
globalId++;
}
}
for (int i = 0; i < n; ++i) {
if (book2Id.find(ListB[i]) == book2Id.end()) {
book2Id[ListB[i]] = globalId;
id2Book[globalId] = ListB[i];
globalId++;
}
}
int globalIdMax = globalId;
father.resize(globalIdMax);
for (int i = 0; i < globalIdMax; ++i) {
father[i] = i;
}
for (int i = 0; i < n; ++i) {
int bookAId = book2Id[ListA[i]];
int bookBId = book2Id[ListB[i]];
merge(bookAId, bookBId);
}
vector<int> sums(globalIdMax, 0);
int maxId = 0, maxValue = 0;
for (int i = 0; i < globalIdMax; ++i) {
int fx = find(i); //not father[i]!
sums[fx]++;
if (sums[fx] > maxValue) {
maxId = fx;
maxValue = sums[fx];
}
}
vector<string> res;
for (int i = 0; i < globalIdMax; ++i) {
if (father[i] == maxId) {
res.push_back(id2Book[i]);
}
}
return res;
}
private:
vector<int> father;
map<string, int> book2Id;
map<int, string> id2Book;
int globalId = 0;
int find(int x) {
if (father[x] == x) return x;
father[x] = find(father[x]);
return father[x];
}
void merge(int x, int y) {
int fx = find(x); //note it is not father[x]
int fy = find(y); //note it is not father[y]
if (fx != fy) {
father[fx] = fy; //not father[x] = fy;
}
}
};
解法2:BFS
这题应该也可以用BFS。思路跟找最大岛屿差不多,即遍历所有书,每次启动一个BFS,找到一个集合之后把集合里的书设为visited,下次BFS只找没有visited过的书。
代码同步在
https://github.com/luqian2017/Algorithm