Buttercola: Zenefits: Validate Graph Binary Tree
Determine if a directed graph is a binary tree. If yes, print out the tree in string format.
Input: (A,B) (A,C) (B,G) (C,H) (E,F) (B,D) (C,E)
Output: (A(B(D)(G))(C(E(F))(H))))
ie.. (parent(child)(child))
If not, print out the error code Error code Type of error
E1 More than 2 children
E2 Duplicate edges -- (A,B) (A,B)
E3 Cycle present
E4 Mulitple roots
E5 Another other error
http://yuanhsh.iteye.com/blog/2207890
Determine if a directed graph is a binary tree. If yes, print out the tree in string format.
Input: (A,B) (A,C) (B,G) (C,H) (E,F) (B,D) (C,E)
Output: (A(B(D)(G))(C(E(F))(H))))
ie.. (parent(child)(child))
If not, print out the error code Error code Type of error
E1 More than 2 children
E2 Duplicate edges -- (A,B) (A,B)
E3 Cycle present
E4 Mulitple roots
E5 Another other error
public
String graphValidBinaryTree(
char
[][] edges) {
if
(edges ==
null
|| edges.length ==
0
) {
return
"E5"
;
}
// Check inDegree for each node
Map<Character, Integer> inDegree =
new
HashMap<>();
for
(
char
[] edge : edges) {
if
(inDegree.containsKey(edge[
1
])) {
int
degree = inDegree.get(edge[
1
]);
inDegree.put(edge[
1
], degree +
1
);
}
else
{
inDegree.put(edge[
1
],
1
);
}
if
(!inDegree.containsKey(edge[
0
])) {
inDegree.put(edge[
0
],
0
);
}
}
// For a valid binary tree, there is one and only one node with inDegree 0, and all the other nodes
// has inDegree 1
char
root =
'\0'
;
int
count =
0
;
for
(
char
vertexId : inDegree.keySet()) {
if
(inDegree.get(vertexId) ==
0
) {
root = vertexId;
count++;
}
if
(count >
1
) {
return
"E4"
;
}
if
(inDegree.get(vertexId) >
1
) {
return
"E4"
;
}
}
// No root
if
(count ==
0
) {
return
"E3"
;
}
// Step 2: transform the edge list to adjList
Map<Character, Set<Character>> adjList =
new
HashMap<>();
for
(
char
[] edge : edges) {
if
(adjList.containsKey(edge[
0
])) {
Set<Character> neighbors = adjList.get(edge[
0
]);
// Duplicate edges
if
(neighbors.contains(edge[
1
])) {
return
"E2"
;
}
else
{
neighbors.add(edge[
1
]);
}
// More than 2 children
if
(neighbors.size() >
2
) {
return
"E1"
;
}
}
else
{
Set<Character> neighbors =
new
HashSet<>();
neighbors.add(edge[
1
]);
adjList.put(edge[
0
], neighbors);
}
}
// Step 3: do a topological sort, if not exist, return E3, cycle presents
// Note: Couldn't use a boolean[] visited, because vertexId is char
// Have to use a set
Set<Character> visited =
new
HashSet<>();
boolean
ans = toplogicalSort(root, visited, adjList);
if
(!ans) {
return
"E3"
;
}
// Step 4: there must be valid binary tree exists, output the results.
String result = treeToString(root, adjList);
return
result;
}
private
boolean
toplogicalSort(
char
vertex, Set<Character> visited, Map<Character, Set<Character>> adjList) {
if
(visited.contains(vertex)) {
return
false
;
}
visited.add(vertex);
Set<Character> neighbors = adjList.get(vertex);
if
(neighbors !=
null
) {
for
(
char
neighbor : neighbors) {
if
(!toplogicalSort(neighbor, visited, adjList)) {
return
false
;
}
}
}
visited.remove(vertex);
return
true
;
}
private
String treeToString(
char
root, Map<Character, Set<Character>> adjList) {
Set<Character> neighbors = adjList.get(root);
if
(neighbors ==
null
|| neighbors.size() ==
0
) {
return
"("
+ root +
")"
;
}
StringBuffer result =
new
StringBuffer();
result.append(
"("
+ root);
for
(
char
neighbor : neighbors) {
result.append(treeToString(neighbor, adjList));
}
result.append(
")"
);
return
result.toString();
}
public
static
void
main(String[] args) {
Scanner sc =
new
Scanner(System.in);
int
numEdges = sc.nextInt();
char
[][] edges =
new
char
[numEdges][
2
];
for
(
int
i =
0
; i < numEdges; i++) {
String edge = sc.next();
edges[i][
0
] = edge.charAt(
1
);
edges[i][
1
] = edge.charAt(
3
);
}
Solution solution =
new
Solution();
String result = solution.graphValidBinaryTree(edges);
System.out.println(result);
sc.close();
}
- public class GraphEdgeTree {
- public static class Edge {
- char from, to;
- public Edge(String exp) {
- String[] nodes = exp.replaceAll("[\\(\\)\\s]", "").split(",");
- from = nodes[0].charAt(0);
- to = nodes[1].charAt(0);
- }
- }
- private Map<Character, Character> map = new HashMap<>();
- private Map<Character, Set<Character>> childMap = new HashMap<>();
- private List<Edge> edges = new ArrayList<>();
- public GraphEdgeTree(String exp) {
- String[] arr = exp.split("\\s");
- for(String str:arr) {
- Edge edge = new Edge(str);
- edges.add(edge);
- map.put(edge.from, edge.from);
- map.put(edge.to, edge.to);
- Set<Character> children = childMap.get(edge.from);
- if(children == null) {
- children = new HashSet<Character>();
- }
- children.add(edge.to);
- childMap.put(edge.from, children);
- }
- }
- public Character find(char x) {
- Character parent = map.get(x);
- if(parent == null || parent == x) {
- return parent;
- }
- return find(parent);
- }
- public void union(char x, char y) {
- Character xp = find(x);
- Character yp = find(y);
- map.put(xp, yp);
- }
- public boolean isEdgeExisted(Edge edge) {
- Character p = map.get(edge.to);
- return p != null && p == edge.from;
- }
- public String buildTree() {
- for(Character key:childMap.keySet()) {
- Set<Character> set = childMap.get(key);
- if(set != null && set.size()>2) {
- return "E1";
- }
- }
- for(Edge edge:edges) {
- if(isEdgeExisted(edge)) {
- return "E2";
- }
- char xp = find(edge.from);
- char yp = find(edge.to);
- if(xp == yp) {
- return "E3";
- }
- union(edge.to, edge.from);
- }
- if(rootNum() > 1) {
- return "E4";
- }
- return null;
- }
- private int rootNum() {
- int cnt = 0;
- for(char key:map.keySet()) {
- if(find(key) == key) {
- cnt++;
- }
- }
- return cnt;
- }
- public String treeString(char root) {
- Set<Character> children = childMap.get(root);
- if(children == null || children.size() == 0) {
- return "("+root+")";
- }
- StringBuilder result = new StringBuilder("("+root);
- for(char child:children) {
- result.append(",").append(treeString(child));
- }
- result.append(")");
- return result.toString();
- }
- public char getRoot() {
- return find(edges.get(0).from);
- }
- public static void main(String[] args) {
- String input = "(A,B) (A,C) (B,G) (C,H) (E,F) (B,D) (C,E)";
- GraphEdgeTree gt = new GraphEdgeTree(input);
- String error = gt.buildTree();
- if(error != null) {
- System.out.println(error);
- } else {
- String result = gt.treeString(gt.getRoot());
- System.out.println(result);
- }
- }
- }
- class TreeNode{
- char value;
- TreeNode left;
- TreeNode right;
- TreeNode(char inp){
- this.value = inp;
- }
- }
- public String sExp(char[][] pair){. visit 1point3acres.com for more.
- // build an adj matrix row is the parent node, col is the child node
- int len = pair.length;
- if (len == 0) return "";
- int[][] adjMat = new int[26][26];
- int[] inNode = new int[26]; // count the incoming edges of each node
- int[] children = new int[26]; // count the number of children of each node
- Map<Character, TreeNode> nodes = new HashMap();
- TreeNode parent, child;
- UnionFind myUnion = new UnionFind(26);
- // build binary tree based on pair
- for (int i = 0; i < len; i++){. more info on 1point3acres.com
- int row = pair[i][0] - 'A';
- int col = pair[i][1] - 'A';. from: 1point3acres.com/bbs
- if (children[row] == 2 && adjMat[row][col] != 1){
- // more than 2 children but not the same edge. 1point 3acres 璁哄潧
- return "E1";
- }else if (adjMat[row][col] == 1){
- // duplicated edges
- return "E2";
- } else if (myUnion.connected(row, col)){. 涓€浜�-涓夊垎-鍦帮紝鐙鍙戝竷
- // if new link connect two that are already in same union there is loop
- return "E3";
- }
- adjMat[row][col] = 1;
- children[row]++;
- inNode[col]++;
- myUnion.connect(row, col);
- connectNodes(pair, nodes, i);
- }
- // check multiple roots. 鍥磋鎴戜滑@1point 3 acres
- int rNum = 0;
- TreeNode root = null;
- for (char x : nodes.keySet()){
- if (inNode[x - 'A'] == 0){
- rNum++;
- if (rNum > 1) return "E4";
- root = nodes.get(x);
- }
- }
- if (root == null) return "E5";
- // convert it to s-expression
- return toSExpression(root);
- }
- // convert it to s-expression. 1point3acres.com/bbs
- String toSExpression(TreeNode root){.鐣欏璁哄潧-涓€浜�-涓夊垎鍦�
- if (root == null) return "";
- return "(" + root.value + toSExpression(root.left) + toSExpression(root.right) + ")";
- }
- // connect parent and child node
- private void connectNodes(char[][] pair, Map<Character, TreeNode> nodes,
- int i) {.1point3acres缃�
- TreeNode parent;
- TreeNode child;
- if (nodes.containsKey(pair[i][0])) parent = nodes.get(pair[i][0]);
- else{.1point3acres缃�
- parent = new TreeNode(pair[i][0]);
- nodes.put(pair[i][0], parent);
- }
- if (nodes.containsKey(pair[i][1])) child = nodes.get(pair[i][1]);. 1point 3acres 璁哄潧
- else{
- child = new TreeNode(pair[i][1]);
- nodes.put(pair[i][1], child);
- }
- if (parent.left == null) parent.left = child;
- else {
- if (parent.left.value < pair[i][1]){
- parent.right = child;
- } else {
- parent.right = parent.left;. 1point 3acres 璁哄潧
- parent.left = child;
- }
- }
- }