例题 104. 二叉树的最大深度。给定一个二叉树,找出其最大深度。
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
return Math.max(maxDepth(root.left) + 1, maxDepth(root.right) + 1);
}
例题 110,平衡二叉树。给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
class Solution {
public boolean isBalanced(TreeNode root) {
if (root == null) {
return true;
}
if (Math.abs(depth(root.left) - depth(root.right)) > 1) {
return false;
}
//继续递归判断
return isBalanced(root.left) && isBalanced(root.right);
}
//树的高度
public int depth(TreeNode node) {
if (node == null) {
return 0;
}
return Math.max(depth(node.left) + 1, depth(node.right) + 1);
}
}
class Solution {
public boolean isBalanced(TreeNode root) {
return depth(root) != -1;
}
public int depth(TreeNode node) {
if (node == null) {
return 0;
}
int l = depth(node.left);
int r = depth(node.right);
//无需继续计算,剪枝
if (l == -1 || r == -1 || Math.abs(l - r) > 1) {
return -1;
}
return Math.max(l, r) + 1;
}
}
例题 543,二叉树的直径。给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
class Solution {
int diameter = 0;
public int diameterOfBinaryTree(TreeNode root) {
if (root == null) {
return 0;
}
depth(root);
return diameter;
}
public int depth(TreeNode node) {
if (node == null) {
return 0;
}
int l = depth(node.left);
int r = depth(node.right);
diameter = Math.max(l + r, diameter);
return Math.max(l, r) + 1;
}
}
例题 437. 路径总和 III。给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
class Solution {
public int pathSum(TreeNode root, int targetSum) {
if (root == null) {
return 0;
}
//注意这里需要以每个结点为起始结点进行遍历
return sumToTarget(root, targetSum) + pathSum(root.left, targetSum) + pathSum(root.right, targetSum);
}
public int sumToTarget(TreeNode node, int targetSum) {
if (node == null) {
return 0;
}
//注意这里也不能 node.val==targetSum 就返回,因为继续往下遍历可能还有满足条件的路径
int count = node.val == targetSum ? 1 : 0;
count += sumToTarget(node.left, targetSum - node.val);
count += sumToTarget(node.right, targetSum - node.val);
return count;
}
}
例题 101. 对称二叉树。给你一个二叉树的根节点 root , 检查它是否轴对称。
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) {
return true;
}
return symmetric(root.left, root.right);
}
public boolean symmetric(TreeNode left, TreeNode right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null) {
return false;
}
return left.val == right.val && symmetric(left.left, right.right) && symmetric(left.right, right.left);
}
}
例题 1110. 删点成林。给出二叉树的根节点 root,树上每个节点都有一个不同的值。如果节点值在 to_delete 中出现,我们就把该节点从树上删去,最后得到一个森林(一些不相交的树构成的集合)。返回森林中的每棵树。你可以按任意顺序组织答案。
class Solution {
public List<TreeNode> delNodes(TreeNode root, int[] to_delete) {
//set比list快很多
Set<Integer> set = new HashSet<>();
for (int delete : to_delete) {
set.add(delete);
}
List<TreeNode> retList = new ArrayList<>();
retList.add(root);
trace(root, set, retList);
return retList;
}
//带返回值的后序遍历
public TreeNode trace(TreeNode node, Set<Integer> set, List<TreeNode> retList) {
if (node == null) {
return node;
}
//如果删除了节点,可以断上层指针
node.left = trace(node.left, set, retList);
node.right = trace(node.right, set, retList);
if (set.contains(node.val)) {
retList.remove(node);
if (node.left != null) {
retList.add(node.left);
}
if (node.right != null) {
retList.add(node.right);
}
node = null;
}
return node;
}
}
例题 637. 二叉树的层平均值。给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。
public List<Double> averageOfLevels(TreeNode root) {
List<Double> retList = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
double sum = 0;
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
sum += node.val;
}
retList.add(sum / size);
}
return retList;
}
例题 105. 从前序与中序遍历序列构造二叉树。给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder.length == 0) {
return null;
}
//用map存储中序数组的位置关系,方便查找
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i);
}
TreeNode root = build(map, preorder, 0, 0, inorder.length - 1);
return root;
}
//i表示元素在前序中的位置,x表示中序数组的左端点,y表示中序数组的右端点,记录x y 主要是为了计算左右子树长度,用于寻找节点的右节点
public TreeNode build(Map<Integer, Integer> map, int[] preorder, int i, int x, int y) {
if (x > y || i >= preorder.length) {
return null;
}
//tmp为当前元素在中序数组中的位置
int val = preorder[i];
int tmp = map.get(val);
//创建以当前元素为值的节点
TreeNode node = new TreeNode(val);
//左节点所在前序数组中的位置就是i+1
node.left = build(map, preorder, i+1, x, tmp-1);
//右节点所在前序数组中的位置是当前节点的位置+左节点数组长度+1, i+tmp-x+1
node.right = build(map, preorder, i+tmp-x+1, tmp+1, y);
return node;
}
}
例题 889. 根据前序和后序遍历构造二叉树。给定两个整数数组,preorder 和 postorder ,其中 preorder 是一个具有 无重复 值的二叉树的前序遍历,postorder 是同一棵树的后序遍历,重构并返回二叉树。如果存在多个答案,您可以返回其中任何 一个。
class Solution {
public TreeNode constructFromPrePost(int[] preorder, int[] postorder) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < postorder.length; i++) {
map.put(postorder[i], i);
}
TreeNode root = contruct(preorder, map, 0, 0, postorder.length-1);
return root;
}
public TreeNode contruct(int[] preorder, Map<Integer, Integer> map, int i, int x, int y) {
if (x > y) {
return null;
}
if (x == y) {
return new TreeNode(preorder[i]);
}
TreeNode node = new TreeNode(preorder[i]);
int ind = map.get(preorder[i+1]);
//找到当前节点的左节点位置为 i+1,及当前节点左子树的两端边界
node.left = contruct(preorder, map, i+1, x, ind);
//找到当前节点的右节点位置为 ind-x-i+2,及当前节点右子树的两端边界
node.right = contruct(preorder, map, ind-x+i+2, ind+1, y-1);
return node;
}
}
例题 106,从中序与后序遍历序列构造二叉树。给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i);
}
return build(postorder, map, postorder.length-1, 0, postorder.length-1);
}
//i 表示当前节点在postorder中的位置,x y表示当前子树在 inorder中的边界
public TreeNode build(int[] postorder, Map<Integer, Integer> map, int i, int x, int y) {
if (x > y) {
return null;
}
TreeNode node = new TreeNode(postorder[i]);
//post中的元素在inorder中的位置
int ind = map.get(postorder[i]);
//求右子树长度,用于找左子节点
int rightLen = y - ind;
node.left = build(postorder, map, i-rightLen -1, x, ind - 1);
node.right = build(postorder, map, i-1, ind +1, y);
return node;
}
}
例题 144. 二叉树的前序遍历。给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> resList = new ArrayList<>();
if (root == null) {
return resList;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()) {
TreeNode node = stack.pop();
resList.add(node.val);
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
}
return resList;
}
//前序和中序
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> resList = new ArrayList<>();
if (root == null) {
return resList;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode node = root;
while(node != null || !stack.isEmpty()) {
//while循环不断深入寻找左节点
while (node != null) {
resList.add(node.val); //前序加的位置
//stack是为了存储节点用于后续弹出遍历其右节点
stack.push(node);
node = node.left;
}
node = stack.pop();
//resList.add(node.val); //中序加的位置
node = node.right;
}
return resList;
}
//后序
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> retList = new ArrayList<>();
if (root == null) {
return retList;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode node = root;
while(node != null || !stack.isEmpty()) {
while (node != null) {
retList.add(node.val);
stack.push(node);
node = node.right;
}
node = stack.pop();
node = node.left;
}
// 反转retList
Collections.reverse(retList);
return retList;
}
例题 99. 恢复二叉搜索树。给你二叉搜索树的根节点 root ,该树中的 恰好 两个节点的值被错误地交换。请在不改变其结构的情况下,恢复这棵树 。
class Solution {
/**
中序遍历结果应该要是顺序的
*/
TreeNode t1 = null;
TreeNode t2 = null;
TreeNode preNode = null;
public void recoverTree(TreeNode root) {
if (root == null) {
return;
}
inorder(root);
int tmp = t1.val;
t1.val = t2.val;
t2.val = tmp;
}
public void inorder(TreeNode node) {
if (node == null) {
return;
}
inorder(node.left);
if (preNode != null && node.val < preNode.val) {
//t1是记录首次出现降序的位置
if (t1 == null) {
t1 = preNode;
}
//t2不断更新,记录末次出现降序的位置
t2 = node;
}
preNode = node;
inorder(node.right);
}
}
注:这里注意一个问题,由于对 java 是值传递还是引用传递了解的不是特别透彻,因此开始是将代码中的 t1、t2、preNode 都作为参数传入 inorder 方法,结果发现执行完 inorder 之后主函数的 t1 和 t2 还是 null,并没有起到记录节点的作用。
百度后发现 Java 实际上只有值传递,并没有引用传递!!!首先基本数据类型都是值传递,这个毫无疑问。那对象类型是值传递还是引用传递呢?实际上也是值传递,那有人会问了,我传递一个 User 对象到一个方法中,方法里对 User 的 name 字段进行了修改,方法外该对象的 name 确实也被修改了,这不是引用传递吗?解释一下这个的原因:实际上 Java 每定义一个变量,都是在栈中存储,基本数据类型变量的值就是它定义的值,引用变量的值是它指向的对象的地址(对象是在堆中new出来的)。传参时,Java 都是 copy 一份变量的值传递进去,因此对象变量传递的是它指向对象的地址。上述 User 对象改变是对象本身的内容发生了变化,而变量的指向一直没有变化。比如方法内不是直接对对象进行修改,而是重新 new 了一个对象再修改,那么方法外的对象是不会有变化的。这就能理解为什么将 t1、t2 传入方法后最后出来还是 null,因为它的指向一直都是 null,方法里并没有改变null,而是改变了形参的指向。
参考:https://www.jb51.net/article/210037.htm
例题 669. 修剪二叉搜索树。给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null) {
return root;
}
TreeNode node = root;
if (node.val < low) {
//去除当前节点,并且只需要继续查找其右子树
return trimBST(node.right, low, high);
} else if (node.val > high){
//去除当前节点,并且只需要继续查找其左子树
return trimBST(node.left, low, high);
} else {
//在范围内,保留当前节点,继续遍历左右子树
node.left = trimBST(node.left, low, high);
node.right = trimBST(node.right, low, high);
}
return node;
}
例题 208. 实现 Trie (前缀树)。
Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。请你实现 Trie 类:
解法:
class Trie {
//内部类,字典树节点
private class TrieNode {
private boolean isEnd; //标记到当前节点是否是一个插入的单词
private TrieNode[] next; //子节点,最多有26个不同的字母
public TrieNode() {
isEnd = false;
next = new TrieNode[26];
}
}
//字典树的根节点
private TrieNode root;
public Trie() {
root = new TrieNode();
}
public void insert(String word) {
TrieNode node = root;
//遍历word的每个字母,为每个字母建立节点
for (int i = 0; i < word.length(); i++) {
int c = word.charAt(i) - 'a';
if (node.next[c] == null) {
node.next[c] = new TrieNode();
}
node = node.next[c];
}
//为单词打上标记
node.isEnd = true;
}
public boolean search(String word) {
TrieNode node = root;
for (int i = 0; i < word.length(); i++) {
int c = word.charAt(i) - 'a';
if (node.next[c] == null) {
return false;
}
node = node.next[c];
}
return node.isEnd;
}
public boolean startsWith(String prefix) {
TrieNode node = root;
for (int i = 0; i < prefix.length(); i++) {
int c = prefix.charAt(i) - 'a';
if (node.next[c] == null) {
return false;
}
node = node.next[c];
}
return true;
}
}
例题 226. 翻转二叉树。给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
public TreeNode invertTree(TreeNode root) {
if (root == null) {
return root;
}
TreeNode rootleft = root.left;
root.left = invertTree(root.right);
root.right = invertTree(rootleft);
return root;
}
例题 617. 合并二叉树。给你两棵二叉树: root1 和 root2 。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。返回合并后的二叉树。注意: 合并过程必须从两个树的根节点开始。
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null || root2 == null) {
return root1 == null ? root2 : root1;
}
root1.val = root1.val + root2.val;
root1.left = mergeTrees(root1.left, root2.left);
root1.right = mergeTrees(root1.right, root2.right);
return root1;
}
例题 572. 另一棵树的子树。给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if (subRoot == null && root == null) {
return true;
} else if (subRoot == null || root == null) {
return false;
}
return isSub(root, subRoot)
|| isSubtree(root.left, subRoot)
|| isSubtree(root.right, subRoot);
}
public boolean isSub(TreeNode root, TreeNode subRoot) {
if (subRoot == null && root == null) {
return true;
} else if (subRoot == null || root == null) {
return false;
}
return root.val == subRoot.val
&& isSub(root.left, subRoot.left)
&& isSub(root.right, subRoot.right);
}
}
例题 513. 找树左下角的值。给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。假设二叉树中至少有一个节点。
class Solution {
private int res;
private int maxLevel;
public int findBottomLeftValue(TreeNode root) {
res = root.val;
maxLevel = 1;
findBottom(root, 1);
return res;
}
public void findBottom(TreeNode node, int level) {
if (node == null) {
return;
}
//找到第一个最底层节点
if (level > maxLevel) {
maxLevel = level;
res = node.val;
}
findBottom(node.left, level + 1);
findBottom(node.right, level + 1);
}
}
例题 538. 把二叉搜索树转换为累加树。给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
class Solution {
private int sum = 0;
public TreeNode convertBST(TreeNode root) {
if (root == null) {
return root;
}
convertBST(root.right);
root.val += sum;
sum = root.val;
convertBST(root.left);
return root;
}
}
例题 235. 二叉搜索树的最近公共祖先。给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || p == null || q == null) {
return root;
}
if (root.val == p.val) {
return p;
}
if (root.val == q.val) {
return q;
}
if ((root.val > p.val && root.val < q.val)
|| (root.val < p.val && root.val > q.val)) {
return root;
} else if (root.val > p.val && root.val > q.val) {
return lowestCommonAncestor(root.left, p, q);
} else {
return lowestCommonAncestor(root.right, p, q);
}
}
例题 236,二叉树的最近公共祖先。给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//当遇到叶子节点,或者遇到p、q其中一个节点时返回
if (root == null || root == p || root == q) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
//表示 p 和 q 分属当前节点两侧,那当前节点即为公共节点
if (left != null && right != null) {
return root;
} else if (left != null) { //表示p q都在当前节点左侧
return left;
} else {
//表示p q都在当前节点右侧
return right;
}
}
例题 109. 有序链表转换二叉搜索树。给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。
public TreeNode sortedListToBST(ListNode head) {
if (head == null) {
return null;
}
if (head.next == null) {
return new TreeNode(head.val);
}
ListNode slow = head;
ListNode fast = head;
ListNode pre = new ListNode(0);
pre.next = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
pre = pre.next;
}
//slow此时指向中点,pre指向中点的前一个节点,断开连接
pre.next = null;
TreeNode node = new TreeNode(slow.val);
node.left = sortedListToBST(head);
node.right = sortedListToBST(slow.next);
return node;
}
例题 653,两数之和 IV - 输入 BST。给定一个二叉搜索树 root 和一个目标结果 k,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。
class Solution {
Set<Integer> set = new HashSet<>();
public boolean findTarget(TreeNode root, int k) {
if (root == null) {
return false;
}
if (set.contains(k - root.val)) {
return true;
}
set.add(root.val);
return findTarget(root.left, k) || findTarget(root.right, k);
}
}
例题 450. 删除二叉搜索树中的节点。给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
class Solution {
/**
找到待删除的节点以后,需要将该节点的右子节点的最后的左子节点找到进行替换
*/
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) {
return root;
}
if (root.val == key) {
//保存待删除节点的左右节点
TreeNode right = root.right;
TreeNode left = root.left;
TreeNode node = root.right;
//断开待删除节点的左右节点
root.left = null;
root.right = null;
if (node == null) {
return left;
}
if (node.left == null) {
node.left = left;
return node;
}
//pre存储一下上层节点
TreeNode pre = new TreeNode(0);
pre.left = node;
//找到最后的左子节点,作为用于替换的节点
while (node.left != null) {
node = node.left;
pre = pre.left;
}
//找到替换的节点,断开其上层连接
pre.left = null;
//找到替换节点的最后的右子节点,将该节点的右节点指向right;
TreeNode rNode = node;
while (rNode.right != null) {
rNode = rNode.right;
}
node.left = left;
if(right != rNode) {
rNode.right = right;
}
return node;
}
if (root.val > key) {
root.left = deleteNode(root.left, key);
} else {
root.right = deleteNode(root.right, key);
}
return root;
}
}
图有两种表示方式,一种是邻接矩阵,可以建立一个 n× n 的矩阵 G,如果第 i 个节点连向第 j 个节点,则 G[i][j]= 1,反之为 0;如果图是无向的,则这个矩阵一定是对称矩阵,即 G[i][j] = G[j][i]。第二种表示方法是邻接链表:我们可以建立一个大小为 n 的数组,每个位置 i 储存一个数组或者链表,表示第 i 个节点连向的其它节点。邻接矩阵空间开销比邻接链表大,但是邻接链表不支持快速查找 i 和 j 是否相连。
例题 785. 判断二分图。二分图 定义:如果能将一个图的节点集合分割成两个独立的子集 A 和 B ,并使图中的每一条边的两个节点一个来自 A 集合,一个来自 B 集合,就将这个图称为 二分图 。如果图是二分图,返回 true ;否则,返回 false 。
class Solution {
public boolean isBipartite(int[][] graph) {
//给节点涂颜色,0表示未遍历到,1 表示一种颜色,2表示另一种颜色
int[] color = new int[graph.length];
Queue<Integer> queue = new LinkedList<>();
for(int i = 0; i < graph.length; i++) {
if (color[i] == 0) {
queue.offer(i);
color[i] = 1;
}
while (!queue.isEmpty()) {
int node = queue.poll();
for (int j : graph[node]) {
if (color[j] == 0) {
queue.offer(j);
color[j] = color[node] == 1 ? 2 : 1;
} else if (color[j] == color[node]) {
return false;
}
}
}
}
return true;
}
}
例题 210. 课程表 II。现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 1。给你一个数组 prerequisites ,其中 prerequisites[i] = [ai, bi] ,表示在选修课程 ai 前 必须 先选修 bi 。例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示:[0,1] 。
返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。
class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
//维护每个节点对应的后序节点
List<Integer>[] list = new ArrayList[numCourses];
//维护每个节点的入度
int[] indegree = new int[numCourses];
for (int[] pre : prerequisites) {
if (list[pre[1]] == null) {
list[pre[1]] = new ArrayList<>();
}
list[pre[1]].add(pre[0]);
indegree[pre[0]] ++;
}
int[] res = new int[numCourses];
int idx = 0;
//初始化队列,将入度为0的节点添加到队列
Queue<Integer> queue = new LinkedList<>();
for (int i = 0; i < numCourses; i++) {
if (indegree[i] == 0) {
queue.add(i);
}
}
while (!queue.isEmpty()) {
int node = queue.poll();
res[idx++] = node;
if (list[node] == null) {
continue;
}
//后序节点的入度减一
for (int degree : list[node]) {
indegree[degree]--;
if (indegree[degree] == 0) {
queue.add(degree);
}
}
}
//最后可能构不成正确答案,需要返回空数组
return idx == numCourses ? res : new int[0];
}
}