Problem:

Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), write a function to check whether these edges make up a valid tree.

For example:

Given n = 5 and edges = [[0, 1], [0, 2], [0, 3], [1, 4]], return true.

Given n = 5 and edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]], return false.

Show Hint

Note: you can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.

General Analysis:

This problem should give you a good taste of magic algorithm. With the right algorithm, a problem could be solved so elegantly and concisely. My first solution is complex and wrong. 

Big picture, if a graph is a tree, it should possess following qualifications:
1. there is only one source node in the graph.
2. there is no circle in the graph.

Wrong Solution:

public class Solution {
public boolean validTree(int n, int[][] edges) {
if (edges == null)
throw new IllegalArgumentException("edges is null");
boolean[] flag = new boolean[n];
HashMap<Integer, ArrayList<Integer>> map = new HashMap<Integer, ArrayList<Integer>> ();
for (int[] edge : edges) {
flag[edge[1]] = true;
if (map.containsKey(edge[0])) {
map.get(edge[0]).add(edge[1]);
} else{
ArrayList<Integer> item = new ArrayList<Integer> ();
item.add(edge[1]);
map.put(edge[0], item);
}
}
int source = -1;
for(int i = 0; i < n; i++) {
if (!flag[i]) {
if (source == -1)
source = i;
else
return false;
}
}
if (source == -1)
return false;
Arrays.fill(flag, false);
Queue<Integer> queue = new LinkedList<Integer> ();
queue.offer(source);
while (!queue.isEmpty()) {
int cur = queue.poll();
if (flag[cur])
return false;
flag[cur] = true;
if (map.containsKey(cur)) {
ArrayList<Integer> ends = map.get(cur);
for (int end : ends)
queue.offer(end);
}
}
return true;
}
}

Mistake Analysis:

Error cases:
The above solution try to use BFS traversal over the graph to identify if there is a circle in the graph. However, the solution ignores a very important fact: the graph is undirected rather than directed. When means[0 1] [1 0] is actually the same edge, they could be used interchangely. Thus
1. You could not base on whether a node appears on the left side or not, to decide whether it's a source node.
2. Also, you could not based on it to detect a cycle.
The above method only works for Directed Graph.

Analysis:

Actually for Undireted Grpah, we have a classic algorithm to test if there is a circle in the graph. And how many independent sets are there in a graph.

The classic method is called: Union-Find.
Idea: Imagine we could divide the whole grpah into separate sets. (there is no edge to connect two sets). When we read an edge: [start end] from the edge array, it means those two edges actually in the same set, we enlarge the set. If both "start" and "end" have already appeared in the same set before we use the edge, it means a circle was detected. Key skills in the implementation:
1. How to record each node's set? Could it be very complex?
Absolutely no! A node's beloning set could be recored through a int array.
------------------------------------------------------------------------
int[] union = new int[n];
------------------------------------------------------------------------
Before we absorb any edge in the edges array, we treat each node as an independent set. The set number is its own node number.
------------------------------------------------------------------------
Arrays.fill(union, -1);
...
private int findUnion(int[] union, int i) {
if (union[i] == -1)
return i;
...
}
Note : -1 means it has not been connected with any set yet.
------------------------------------------------------------------------ 2. How to find a node's belonging set?
We could use DFS method to find a node's beloning set. private int findUnion(int[] union, int i) {
if (union[i] == -1)
return i;
return findUnion(union, union[i]);
} Note: the way to update union.
for (int[] edge : edges) {
int x = findUnion(union, edge[0]);
int y = findUnion(union, edge[1]);
...
union[y] = x;
}
We can trace a node's directly connected node back, so as to find out the set's no. Note: the set's no is not fixed, it could be affected by the [start, end]'s order, but it does not matter. After a edge was updated, we still could trace through any node back to a same node(it is number is the temporay set no). Suppose we have already known "node_m" in the set 0. we update the union array through following way:
int x = findUnion(union, edge[0]);
int y = findUnion(union, edge[1]);
union[y] = x; Case 1: [node_m node_n]
case 2: [node_n node_m] for case 1:
x = findUnion(union, node_m) = 0;
y = findUnion(union, node_n) = node_n;
union[node_n] = 0;
When we use DFS method, we can track node_n's set no is 0. for case 2:
x = findUnion(union, node_n) = node_n;
y = findUnion(union, node_m) = 0;
union[0] = node_n
When we use DFS method, we can track all nodes in the set back to node_n. Haha!!!So tricky and powerful!
Thus, we could easily detect if there is a circle in the graph.
if (x == y)
return false; 3. How to detect if there are more than two independt sets in the graph?
You may think about through counting how many elements in the union array is "-1". Acutally, we should use a property of tree to answer this question very quickly.
For a tree with N nodes in total, it must have N-1 edges.
return edges.length == n - 1;
If there are more than N-1 edges, it must have circle.
If there are edges < N-1, there are must more than 1 sets(more than two sources).

Solution:

public class Solution {
public boolean validTree(int n, int[][] edges) {
if (edges == null)
throw new IllegalArgumentException("edges is null");
int[] union = new int[n];
Arrays.fill(union, -1);
for (int[] edge : edges) {
int x = findUnion(union, edge[0]);
int y = findUnion(union, edge[1]);
if (x == y)
return false;
union[y] = x;
}
return edges.length == n - 1;
} private int findUnion(int[] union, int i) {
if (union[i] == -1)
return i;
return findUnion(union, union[i]);
}
}

[LeetCode#261] Graph Valid Tree的更多相关文章

  1. [LeetCode] 261. Graph Valid Tree 图是否是树

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

  2. [LeetCode] 261. Graph Valid Tree _ Medium tag: BFS

    Given n nodes labeled from 0 to n-1 and a list of undirected edges (each edge is a pair of nodes), w ...

  3. 261. Graph Valid Tree

    题目: Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nod ...

  4. [Locked] Graph Valid Tree

    Graph Valid Tree Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is ...

  5. [LeetCode] Graph Valid Tree 图验证树

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

  6. LeetCode Graph Valid Tree

    原题链接在这里:https://leetcode.com/problems/graph-valid-tree/ 题目: Given n nodes labeled from 0 to n - 1 an ...

  7. Leetcode: Graph Valid Tree && Summary: Detect cycle in undirected graph

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

  8. Graph Valid Tree -- LeetCode

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

  9. [Swift]LeetCode261.图验证树 $ Graph Valid Tree

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

随机推荐

  1. Bash判断是否是root

    #!/bin/bash ]; then echo "Not Root" exit fi

  2. [验证码实现] Captcha 验证码类,一个很个性的验证码类 (转载)

    点击下载 Captcha.zip /// <summary> /// 类说明:条码生成类 /// 编 码 人:苏飞 /// 联系方式:361983679 /// 更新网站:[url=htt ...

  3. Linked Server for SQL Server 2012(x64) to Oracle Database 12c(x64)

    因为把两台数据库装了同一台机机器上,所以没有安装oracle Client的部分,Oracle部分使用netca创建的Net Service Name,使用tnsping以及登入方式的确认用户权限的以 ...

  4. 网页快照 - C#实现

    /// <summary> /// 图片类型枚举 /// </summary> public enum ImageType { GIF = , JPG = , PNG = } ...

  5. 【转】Spring.NET学习笔记——目录

    目录 前言 Spring.NET学习笔记——前言 第一阶段:控制反转与依赖注入IoC&DI Spring.NET学习笔记1——控制反转(基础篇) Level 200 Spring.NET学习笔 ...

  6. boost::bind实践

    第一部分源码为基础实践: /*Beyond the C++ Standard Library ( An Introduction to Boost )[CN].chm*/ /*bind的用法*/ #i ...

  7. ACM YTU 挑战编程 字符串 Problem A: WERTYU

    Problem A: WERTYU Description A common typing error is to place yourhands on the keyboard one row to ...

  8. Zend Studio 11.0.2 破解和汉化

    本方法适用于Zend Studio 11.0.2,亲测,其他版本未知. 破解方法:覆盖安装目录 plugins 里同名文件,启动任意输入即可注册. Windows版下载地址:http://downlo ...

  9. 使用 fn 标签 解决字数过多时用省略号代替 .............................

    list列表单条记录某字段大于10就后面添加省略号(如:内容只是显示开始的10个字,后面的用省略号代替) 在list列表中单条记录某字段大于10就后面添加省略号, 首先引入 jstl标签: <% ...

  10. android code 和js的交互

    小弟现在需要android code 和js的交互.出现了问题,求大家带一带啊. 我的页面:<!DOCTYPE html><html lang="en">& ...