2 <= skills.length <= 10^5
1 <= skills[i].length <= 4
1 <= skills[i][j] <= 1000
skills[i]
中不包含重复元素
解题思路:注意观察数据,题目不能使用平方级算法。每个人掌握的技能数量是极少的,不超过4个,而总技能数量也很少,不超过1000。第一印象:哈希或字典树?
显然应该想办法快速找到互相包含的集合(找互斥的集合不好处理,且无法优化)。如果集合A包含集合B,那么B是A的子集,而A的子集最多是16个,判断B是否是A的子集可以用哈希法(map)解决。算法图示如下,先排序,构造子集,进行快速比对。
class Solution
{
public:
int coopDevelop(vector<vector<int>>& a)
{
sort(a.begin(),a.end(),[](const auto& a,const auto& b){
return a.size()<b.size();});/**< 按集合中元素个数排序 */
unordered_map<long long,int>mp;/**< 用map会超时 */
long long i,j,k,ans=a.size()*(a.size()-1)/2,mod=1e9+7;
for(i=0; i<a.size(); i++)
{
sort(a[i].begin(),a[i].end());
for(j=1; j<(1<<a[i].size()); j++)
{ /**< 统计a[i]子集个数 */
long long subset=0;
for(k=0; k<a[i].size(); k++)
if(j&1<<k) /**< 因为不超过1000,所以用1000做哈希,用其他数字可能出错 */
subset=subset*1000+a[i][k];
ans-=mp[subset];
}
long long subset=0;/**< 将a[i]加入map */
for(k=0; k<a[i].size(); k++)
subset=subset*1000+a[i][k];
mp[subset]++;
}
return ans%mod;
}
};