左神:有序表、并查表等

1. 岛问题(并查集)

方法一:普通版
思路:
    利用infect函数把一片1统一变成2,本质上是记录访问过的1
 
//"感染"函数
/*
* vec:必须传引用,因为修改的值需要保存,并且引用的是原容器的副本,所以不会修改原先内容
* i:行
* j:列
* m:行界限
* n:列界限
*/
void infect(vector<vector<int>>& vec, int i, int j, int m, int n) {
	if (i < 0 || i >= m || j < 0 || j >= m || vec[i][j] != 1)return;
	//vec[i][j]=1,修改成2
	vec[i][j] = 2;
    //由于for循环遍历的方向是从左到右,从上到下,因此每个1必定是从它的左边或上边抵达,因此只需向右和向下走
	infect(vec, i, j + 1, m, n);
	infect(vec, i + 1, j, m, n);
}
递归时间复杂度: O(N*M)

int countIslands(vector<vector<int>>vec) {//不传引用避免修改原容器里的内容
	int m = vec.size();//行
	int n = vec[0].size();//列
	int res = 0;//岛的数量
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			if (vec[i][j] == 1) {
				//到达1处才开始感染,每调用一次感染岛数+1
				res++;
				infect(vec, i, j, m, n);
			}
		}
	}
	return res;
}


并查集:向上指的结构
//样本进来包一层,叫做元素
template<typename V>
class Element{
public:
	V value;
	Element(V value) {
		this->value = value;
	}
};

//定义并查集结构
template<typename V>
class UnionFindSet {
public:
	//key元素对应value元素"圈"
	map<V, Element<V>>elementMap;
	//value元素是key元素的父
	map<Element<V>, Element<V>>fatherMap;
	//key元素是某个集合的代表元素,value是该集合的大小
	map<Element<V>, int>sizeMap;
	//并查集在构建时要求用户把样本都传过来
	UnionFindSet(list<V>ls) {
		for (V value : list) {
			Element<V>element = new Element<V>(value);
			elementMap[value] = element;
			fatherMap[element] = element;
			sizeMap[element] = 1;
		}
	}

	Element<V>findHead(Element<V>element) {
		stack<Element<V>>path;
		while (element != fatherMap[element]) {
			path.push(element);
			element = fatherMap[element];
		}
		//把结构变成扁平的,降低高度
		//不用考虑每个元素集合size的变化,因为改变的元素都不是代表元素
		while (!path.isEmpty()) {
			fatherMap[path.top] = element;
			path.pop();
		}
		return element;
	}

	bool isSameSet(V a, V b) {
		if (elementMap.find(a) != elementMap.end() && elementMap.find(b) != elementMap.end()) {
			return findHead(elementMap[a]) == findHead(elementMap[b]);
		}
		return false;
	}

	void union(V a, V b) {
		if (elementMap.find(a) != elementMap.end() && elementMap.find(b) != elementMap.end()) {
			Element<V>aF = findHead(elementMap[a]);
			Element<V>bF = findHead(elementMap[b]);
			if (aF != bF) {
				Element<V>big = sizeMap[aF] > sizeMap[bF] ? aF : bF;
				Element<V>small = big == aF ? bF : aF;
				fatherMap[small] = big;
				sizeMap[big] += sizeMap[small];
				sizeMap.erase(small);
			}
		}
	}
};

方法二:并行算法
问题1:切开图分配给不同的CPU之后,可能会把原本连通的切断。
解决1:记录切割边边界点的感染源。不同的感染源感染到的点分配在不同集合中,最后通过能否合并集合来算出实际岛数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jomo.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值