数据结构 图 判断图是否连通
图的遍历方法有dfs,bfs先遍历一遍图,判断是否所有的节点都遍历到
并查集的方法合并节点,最后数一共有多少集合,如果集合是1,证明连通。
参考这篇博客http://www.cnblogs.com/noKing/p/8018609.html
LeetCode547 Friend Circles朋友圈 代码 好理解版本
【思路】灵感来源于上面的参考博客,先生产一维数组p,数组的值和下标一致。遍历二维数组,给每个值找一个老大。相当于形成了一条条链表。
如0和1是朋友,将0->1
0和2是朋友 发现p[0]已经不是0了,说明0有老大了,去找他的老大,发现是1,因为p[1]==1,将p[1]置为2。现在0->1->2了。
安装上面思路编写代码,发现如下问题。
以下代码再运行[[1,1,1,1,1],[1,1,1,1,1],[1,1,1,1,1],[1,1,1,1,1],[1,1,1,1,1]]
用例时出错,死循环。
原因在于执行一下代码出现问题。假设第一行0和1,2,3,4已经合并完。按照我的代码的意思
0->1->2->3->4,遍历到第2行的时候,1要和2合并,这时候1会一直找到4,发现4==p[4],把p[4]置为2,这里逻辑就出错了。正确的应该判断1和2是不是已经有一个相同的根节点了。
while (node != p[node]) {
node = p[node];
}
p[node] = j;
问题代码
public class Solution {
public static void main(String[] args) {
int[][] M = {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}};
System.out.println(findCircleNum(M));
}
public static int findCircleNum(int[][] M) {
int m = M.length;
int[] p = new int[m];
for (int i = 0; i < m; i++) {
p[i] = i;
}
for (int i = 0; i < m; i++) {
for (int j = i+1; j < m; j++) {
if (M[i][j] == 1) {
int node = p[i];
while (node != p[node]) {
node = p[node];
}
p[node] = j;
}
}
}
//遍历p,看还有多少个i=p[i],满足i=p[i]的节点都是顶点
int group = 0;
for (int i = 0; i < m; i++) {
if (i == p[i]) {
++group;
}
}
return group;
}
}
改进方法,每次联合两个数的时候先判断是否有共同的根节点。
跑如下测试用例出错
[[1,1,0,0,0,0,0,0,0,0],[1,1,0,0,0,1,0,1,0,0],[0,0,1,0,1,0,0,1,0,0],[0,0,0,1,0,0,1,0,0,0],[0,0,1,0,1,0,1,0,0,0],[0,1,0,0,0,1,0,1,1,0],[0,0,0,1,1,0,1,0,0,0],[0,1,1,0,0,1,0,1,0,0],[0,0,0,0,0,1,0,0,1,0],[0,0,0,0,0,0,0,0,0,1]]
输出:
3
预期:
2
int[][] M ={{1,1,0,0,0,0,0,0,0,0},
{1,1,0,0,0,1,0,1,0,0},
{0,0,1,0,1,0,0,1,0,0},
{0,0,0,1,0,0,1,0,0,0},
{0,0,1,0,1,0,1,0,0,0},
{0,1,0,0,0,1,0,1,1,0},
{0,0,0,1,1,0,1,0,0,0},
{0,1,1,0,0,1,0,1,0,0},
{0,0,0,0,0,1,0,0,1,0},
{0,0,0,0,0,0,0,0,0,1}};
debug发现是break错了,给为continue就过了
package 牛客刷题.LeetCode.并查集.朋友圈;
/**
* Created by Administrator on 2018/5/28 0028.
*/
public class Solution {
public static void main(String[] args) {
//int[][] M = {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}};
int[][] M ={{1,1,0,0,0,0,0,0,0,0},
{1,1,0,0,0,1,0,1,0,0},
{0,0,1,0,1,0,0,1,0,0},
{0,0,0,1,0,0,1,0,0,0},
{0,0,1,0,1,0,1,0,0,0},
{0,1,0,0,0,1,0,1,1,0},
{0,0,0,1,1,0,1,0,0,0},
{0,1,1,0,0,1,0,1,0,0},
{0,0,0,0,0,1,0,0,1,0},
{0,0,0,0,0,0,0,0,0,1}};
System.out.println(findCircleNum(M));
}
public static int findCircleNum(int[][] M) {
int m = M.length;
int[] p = new int[m];
for (int i = 0; i < m; i++) {
p[i] = i;
}
for (int i = 0; i < m; i++) {
for (int j = i+1; j < m; j++) {
if (M[i][j] == 1) {
int firstRoot = find(i, p);
int secondRoot = find(j, p);
if (firstRoot == secondRoot) {
break;
} else {
p[firstRoot] = j;
}
}
}
}
//遍历p,看还有多少个i=p[i],满足i=p[i]的节点都是顶点
int group = 0;
for (int i = 0; i < m; i++) {
if (i == p[i]) {
++group;
}
}
return group;
}
//找每个节点的根节点下标
public static int find(int a,int[] p) {
int node = a;
while (node != p[node]) {
node = p[node];
}
return node;
}
}
通过代码
package 牛客刷题.LeetCode.并查集.朋友圈;
/**
* Created by Administrator on 2018/5/28 0028.
*/
public class Solution {
public static void main(String[] args) {
//int[][] M = {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}};
int[][] M ={{1,1,0,0,0,0,0,0,0,0},
{1,1,0,0,0,1,0,1,0,0},
{0,0,1,0,1,0,0,1,0,0},
{0,0,0,1,0,0,1,0,0,0},
{0,0,1,0,1,0,1,0,0,0},
{0,1,0,0,0,1,0,1,1,0},
{0,0,0,1,1,0,1,0,0,0},
{0,1,1,0,0,1,0,1,0,0},
{0,0,0,0,0,1,0,0,1,0},
{0,0,0,0,0,0,0,0,0,1}};
System.out.println(findCircleNum(M));
}
public static int findCircleNum(int[][] M) {
int m = M.length;
int[] p = new int[m];
for (int i = 0; i < m; i++) {
p[i] = i;
}
for (int i = 0; i < m; i++) {
for (int j = i+1; j < m; j++) {
if (M[i][j] == 1) {
int firstRoot = find(i, p);
int secondRoot = find(j, p);
if (firstRoot == secondRoot) {
continue;
} else {
p[firstRoot] = j;
}
}
}
}
//遍历p,看还有多少个i=p[i],满足i=p[i]的节点都是顶点
int group = 0;
for (int i = 0; i < m; i++) {
if (i == p[i]) {
++group;
}
}
return group;
}
//找每个节点的根节点下标
public static int find(int a,int[] p) {
int node = a;
while (node != p[node]) {
node = p[node];
}
return node;
}
}