最多連續數的子集(並查集+啓發式合併)

題目描述:給一個整數數組a[], 找到其中包含最多連續數的子集,比如給:15, 7, 12, 6, 14, 13, 9, 11,則返回: 5:[11, 12, 13, 14, 15]

思路:初始化每個樹子集一個集合,預處理每個數的數值哈希到一張表中,內容存下標,掃一次數組,每次取找val+1以及val-1的數,如果找到了把兩者的集合合併,合併時可以按子集的大小進行啓發式合併,即小的集合合併到多的集合中,這樣能夠儘量使並查集的所有子節點都接近根位置,加快查詢效率。

Code

int find(int x) {
    if(x == fa[x]) return x;
    return fa[x] = find(fa[x]);
}

void join(int x, int y) { //合併
    int px = find(x);
    int py = find(y);
	if(px == py) return ;
    if(rank[px]>rank[py]) {
		fa[py] = px;
		rank[px] += rank[py];
	} else {
		fa[px] = py;
		rank[py] += rank[px];
	}
}

void solve() {
	memset(rank, 0, sizeof(rank));
	memset(fa, 0, sizeof(fa));
	unordered_map<int, int> hash;
	hash.clear();
	for(int i=1; i<=n; i++) {
		rank[i]=1;
		fa[i]=i;
		hash[val[i]]=i; //鍵唯一,附帶去重
	} //預處理
	for(int i=1; i<=n; i++) {
		int cur = val[i];
		if(hash.find(cur-1) != hash.end()) join(i, hash[cur-1]);
		if(hash.find(cur+1) != hash.end()) join(i, hash[cur+1]);
	}
	int maxSize = rank[1], maxIndex = 1;
	for(int i=2; i<=n; i++) {
		if(rank[i] > maxSize)
			maxSize=rank[i], maxIndex=i; //記錄最大的那個團根
	}
	cout << maxSize << endl;
	for(int i=1; i<= n; i++)
		if(rank[i] == maxSize && hash[val[i]] == i)
			cout << val[i] << ' ';
	cout << endl;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章