题目
解析
这道题目给的是一个邻接矩阵。乍一看会觉得跟695 max area of islands是一模一样的,其实不然。695的矩阵展示的是每个1和0的实际位置,而这题则不是。应该说695的矩阵表示某种意义上说已经是无向图的一种表示了,但是这道题目不是。
具体的区别是这样的,这题的核心目标是找一个无向图中的连通分量,而他的每一行或者列代表着一个节点。所以这个矩阵一定是对称且行数等于列数。而对于695来说矩阵每一个位置就代表一个节点。
虽然这两道题表示方法不同,但是解法的本质是一样的。695可以通过将访问过的节点置零的方式来标记已经访问过的节点,而这边用这样的方式会很麻烦。这题的话可以构建一个长度为n的像量,像量每个元素代表一个节点是否被访问过。然后我们遍历所有的n个节点,对于每个节点做DFS或者BFS即可
DFS解法
class Solution:
def findCircleNum(self, M: List[List[int]]) -> int:
def dfs(i):
visited[i] = True
for j in range(len(M)):
if M[i][j]==1 and visited[j] == False:
dfs(j)
count = 0
visited = [False]*len(M)
for i in range(len(M)):
if visited[i] == False:
dfs(i)
count += 1
return count
BFS解法
class Solution:
def findCircleNum(self, M: List[List[int]]) -> int:
visited = [False]*len(M)
count = 0
q = collections.deque()
for i in range(len(M)):
if visited[i] == False:
q.append(i)
visited[i] = True
while q:
curr = q.popleft()
for j in range(len(M)):
if M[curr][j] == 1 and visited[j] == False:
visited[j] = True
q.append(j)
count+=1
return count
这里想要提一点就是,虽然BFS和DFS解法的时间复杂度都是O(n*n),但是直观上来讲对于这题应该是DFS更快。实际上run出来的结果也证明了这点,DFS解法超过了95%的提交,而BFS只超过了15%的提交,不过差别这么大也是比较让人惊讶。
还有一个注意的问题是,其实visited[i]=True也可以移到while里面写visited[curr]=True,但是这样其实不合理,在BFS中,visited代表的是是否进过队列,所以一律应该在进队列之后就加入visited
C++版本DFS
class Solution {
public:
int findCircleNum(vector<vector<int>>& M) {
vector<bool> visited(M.size(),false);
int count = 0;
for (int i=0;i<M.size();++i){
if (visited[i] == false){
dfs(M,i,visited);
++count;
}
}
return count;
}
void dfs(vector<vector<int>>& M,int i, vector<bool>& visited){
visited[i] = true;
for (int j=0;j<M.size();++j){
if (M[i][j]==1 && visited[j]==false){
dfs(M,j,visited);
}
}
}
};