二叉树下leecode总结 二叉树
n 座城市,从 0 到 n-1 编号,其间共有 n-1 条路线。因此,要想在两座不同城市之间旅行只有唯一一条路线可供选择(路线网形成一颗树)。去年,交通运输部决定重新规划路线,以改变交通拥堵的状况。
路线用 connections 表示,其中 connections[i] = [a, b] 表示从城市 a 到 b 的一条有向路线。
今年,城市 0 将会举办一场大型比赛,很多游客都想前往城市 0 。
请你帮助重新规划路线方向,使每个城市都可以访问城市 0 。返回需要变更方向的最小路线数。
题目数据 保证 每个城市在重新规划路线方向后都能到达城市 0 。
```java
class Solution {
/*public int minReorder(int n, int[][] connections) {
// 维护含有城市i的connection的index 不一样的邻接图构造方法
List<List<Integer>> tree = new ArrayList<>();
for (int i = 0; i < n; i++) {
tree.add(new ArrayList<>());
}
for (int i = 0; i < n - 1; i++) {
tree.get(connections[i][0]).add(i);
tree.get(connections[i][1]).add(i);
}
int ans = 0;
// 表示第i条边是否已访问
boolean[] visited = new boolean[n - 1];
Queue<Integer> queue = new LinkedList<>();
queue.offer(0);
while (!queue.isEmpty()) { //广度优先遍历
int node = queue.poll();
for (int idx : tree.get(node)) {
if (visited[idx]) {
continue;
}
visited[idx] = true;
int a = connections[idx][0];
int b = connections[idx][1];
if (a == node) {
ans++;
a = b;
}
queue.offer(a);
}
}
return ans;
}*/
//以下是错误的写法可以看下面的写法
/*public int minReorder(int n, int[][] connections) {
Set<Integer> available = new HashSet<>();
available.add(0);
int change = 0;
for (int[] line : connections) {
if (available.contains(line[1])){
available.add(line[0]);
} else if(available.contains(line[0])){
change++;
available.add(line[1]);
}
}
return change;
}*/
//这是改进的错误的写法
public int minReorder(int n, int[][] connections) {
Set<Integer> eUnCheck = new HashSet<Integer>() {{
for (int i = 0; i < n - 1; i++) {
add(i);
}
}};
Set<Integer> vConnected = new HashSet<>();
vConnected.add(0);
int res = 0;
while (!eUnCheck.isEmpty()) {
Iterator<Integer> it = eUnCheck.iterator();
while (it.hasNext()) {
int i = it.next();
int[] conn = connections[i];
if (vConnected.contains(conn[1])) {
vConnected.add(conn[0]);
it.remove();
} else if (vConnected.contains(conn[0])) {
vConnected.add(conn[1]);
it.remove();
res++;
}
}
}
return res;
}
//这是用并查集做
/* public int minReorder(int n, int[][] connections) {
int[] un = new int[n];
Arrays.fill(un, -1);
int ans = 0;
for (int i = 0; i < n - 1; i++) {
int p1 = getRoot(connections[i][0], un);
int p2 = getRoot(connections[i][1], un);
if (p1 == 0) {
int k = connections[i][1];
while (k != -1) {
k = un[k];
ans++;
}
un[p2] = 0;
} else {
if (p2 == 0 && un[connections[i][0]] != -1) {
int k = connections[i][0];
while (un[k] != -1) {
k = un[k];
ans++;
}
ans++;
}
un[p1] = p2;
}
}
return ans;
}*/
//优秀的答案,除了端点处的节点,任何节点都有一个next,然后用dfs去做,这个答案比较好
public int minReorder(int n, int[][] connections) {
// 构图
Node[] graph = new Node[n];
for (int[] connection : connections) {
int from = connection[0], to = connection[1];
graph[from] = new Node(to, true, graph[from]);
graph[to] = new Node(from, false, graph[to]);
}
boolean[] visited = new boolean[n];
// 修改的数目
return dfs(0, graph, visited);
}
private int dfs(int cur, Node[] graph, boolean[] visited) {
int res = 0;
visited[cur] = true;
for (Node tmp = graph[cur]; tmp != null; tmp = tmp.next) {
if (visited[tmp.ver]) continue;
if (tmp.flag) res++;
res += dfs(tmp.ver, graph, visited);
}
return res;
}
}
class Node {
int ver;
// 标识反向
boolean flag;
Node next;
Node(int ver, boolean flag, Node next) {
this.ver = ver;
this.flag = flag;
this.next = next;
}
}