LintCode 805: Maximum Association Set (并查集和BFS好题)

  1. 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值