ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

力扣547-省份数量

2021-10-13 21:58:10  阅读:189  来源: 互联网

标签:遍历 int 查集 isConnected 力扣 547 ans 省份


第八十一天 --- 力扣547-省份数量

题目一

力扣:547

在这里插入图片描述
在这里插入图片描述

思路

经典的图论问题,因为城市间联通等效于边,城市等效于点。

并查集

(有关并查集详细讲解,见我这篇博客力扣648冗余连接,在此不再赘述。)
1、本题其实我第一眼拿来,就是一个并查集问题,因为有很明显的提示—>省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。这里很明显突出了一个省属于一个互相连通的集合,所以维护这种集合问题,最好就用并查集。
2、这个题和经典问题“外星人割网线”,这个题很像,最开始我们维护的并查集内,有N个独立的省份,随着对邻接矩阵的读取,逐渐不同城市间有了连接,他们便属于了一个省份,所以合并一次,ans–,不要重复合并,所以合并之前一定要卡看,他们属不属于一个省份。这样到最后,ans就是省份数量

DFS

1、这个题其实很类似于网格类题目,比如力扣200岛屿数量岛屿数量给的是方格,方格上只能走四个方向,并且他给的只是网格中点的状态,而不是邻接矩阵。
2、这个题就不一样了,本题目任意两个城市之间都有可能有连线,所以从每个点出发,得暴力枚举他所有可能去的点,并且给的是邻接表,表示图的关系。
3、从头遍历每一个城市,如果没走过,说明该城市所在省份树没走过,所以走一遍省份树,到过的城市标记好,每走这么一次dfs,说明一个省份。
4、遍历省份树的时候就和树上的遍历一致,注意他会分出多少可能的枝条就行,因为任意两个城市之间都有可能有连线,所以从每个点出发,得暴力枚举他所有可能去的点,该点得是在邻接矩阵中值为1,代表相连,并且没走过,防止死循环。
5、树形DFS遍历,每找到一个可以到的并且没到过的点,就走下去,那一个枝条完事回溯回来之后,在横向继续找

BFS

这个思路没啥好讲的,就是在按照树形遍历某个省份的时候,不用递归,用队列维护接下来要走的城市,别的和DFS一致。

代码

并查集

注:
1、我们并查集内部是从1到n来维护的,所以传进来的数据得+1
2、我们采用了压缩查询加快速度
3、因为是无向图,所以只需要遍历一半即可.

class query_set {  封装并查集操作
public:
	query_set(int n) {
		this->n = n;
		for (int i = 0; i <= n; i++) { 初始化,每个人都代表一个集合,所以代表元是自己
			father[i] = i;
		}
	}
	int find(int item) { 
		if (item <= 0 || item > n) {  越界处理
			return 0;
		}
		if (father[item] == item) {
			return item;
		}
		father[item] = find(father[item]);  实现了压缩查询
		return father[item];
	}
	void merge(int i, int j) {  合并操作,即相应集合代表元,一个连到另一个人之后
		father[find(i)] = find(j);
	}
private:
	int father[1000];  并查集
	int n;
};
class Solution {
public:
	int findCircleNum(vector<vector<int>>& isConnected) {
		int n = isConnected.size();
		int ans = n;
		query_set qs(n);
		for (int i = 0; i < n; i++) {
			for (int j = i + 1; j < n; j++) {  自己连自己没意义,从下一位开始,还能实现遍历一半操作
				if (ans == 1) {   极限情况,一个省,剩下不用看了,直接是答案
					return ans;
				}
				if (isConnected[i][j] == 1) {
					if (qs.find(i + 1) != qs.find(j + 1)) {  不是一个省的
						qs.merge(i + 1, j + 1);
						ans--;
					}
				}
				else {
					continue;
				}
			}
		}
		return ans;
	}
};

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):

在这里插入图片描述

在这里插入图片描述

DFS

注意:为了防止重复,所以每次扩展新的点的时候,新的点不能是走过的,反之会陷入死循环。

class Solution {
public:
	vector<vector<int>> isConnected;  临时所用邻接矩阵
	bool is_visit[220] = {};  访问状态
	int ans = 0;
	int n = 0; 省份数目
	int findCircleNum(vector<vector<int>>& isConnected) {
		this->isConnected = isConnected;
		n = isConnected.size();
		for (int i = 0; i < n; i++) {  每次找没访问过的点进行判断,找到新的省份
			if (!is_visit[i]) {
				ans++;
				dfs(i);
			}
		}
		return ans;
	}
	void dfs(int i) {
		is_visit[i] = true; 新访问的点,置true
		for (int j = 0; j < n; j++) {  这里就是树形DFS遍历,每找到一个可以到的并且没到过的点,就走下去,那一个枝条完事回溯回来之后,在横向继续找
			if (isConnected[i][j] == 1 && !is_visit[j]) {
				dfs(j);
			}
		}
	}
};

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):

在这里插入图片描述

在这里插入图片描述

BFS

注意:为了防止重复,所以每次扩展新的点的时候,新的点不能是走过的,反之会陷入死循环。

class Solution {
public:
	vector<vector<int>> isConnected;  临时所用邻接矩阵
	bool is_visit[220] = {};  访问状态
	int ans = 0;
	int n = 0; 省份数目
	int findCircleNum(vector<vector<int>>& isConnected) {
		this->isConnected = isConnected;
		n = isConnected.size();
		for (int i = 0; i < n; i++) {  每次找没访问过的点进行判断,找到新的省份
			if (!is_visit[i]) {
				ans++;
				bfs(i);
			}
		}
		return ans;
	}
	void bfs(int i) {
		queue<int> q;
		q.push(i);
		while (!q.empty()) { 用队列维护
			int tmp = q.front();
			q.pop();
			is_visit[tmp] = true;
			for (int j = 0; j < n; j++) { 这个就是一个类似树形的遍历过程,每层都横向的找到所有可能的点,然后存入队列
				if (isConnected[tmp][j] == 1 && !is_visit[j]) {
					q.push(j);
				}
			}
		}
	}
};

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):

在这里插入图片描述

在这里插入图片描述

标签:遍历,int,查集,isConnected,力扣,547,ans,省份
来源: https://blog.csdn.net/qq_45678698/article/details/120752468

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有