先根(根左右)
思路:
1. 栈中放入根 2. 遍历栈 先放入右节点 然后放入左姐递单
public List<Integer> preOrderTraversal(TreeNode root) {
LinkedList<Integer> res = new LinkedList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
res.add(node);
//注意是根 左 右 所以先放入右节点到栈中
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
}
return res;
}
中根(左根右)
思路:
1. 将根节点入栈 2. 将所有左节点入栈 3. 每次出栈后 放入右节点
public List<Integer> inOrderTraversal(TreeNode root) {
LinkedList<Integer> res = new LinkedList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
res.add(root.val);
root = root.right;
}
return res;
}
后根遍历(左右根)
思路:
1. 通过栈 找到最右侧节点 2. 遍历顺序是 根右左 3. 采用头插入 结果是左右根
public List<Integer> postorderTraversal(TreeNode root) {
LinkedList<Integer> res = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
while (root != null || !stack.isEmpty()) {
while (root != null) {
//因为左右根 所以头插入
res.addFirst(root.val);
stack.push(root);
root = root.right;
}
root = stack.pop().left;
}
return res;
}
层次遍历
思路: 通过队列 每次遍历一层
public List<List<Integer>> levelOrderTraversal(TreeNode root) {
LinkedList<List<Integer>> res = new LinkedList<>();
if (root == null) return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
int level = 0;
while (!queue.isEmpty()) {
res.add(new ArrayList<>());
for (int i = 0; i < queue.size(); i++) {
TreeNode node = queue.poll();
res.get(level).add(node);
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
level++:
}
return res;
}
根据先跟和中跟构建树
public TreeNode buildTree(int[] pre, int[] in) {
if (pre == null || in == null || pre.length == 0 || in.length == 0) return null;
if (pre.length != in.length) return null;
TreeNode root = new TreeNode(pre[0]);
for (int i = 0; i < pre.length; i++) {
if (in[i] == pre[0]) {
root.left = buildTree(Arrays.copyOfRange(pre, 1, i+1), Arrays.copyOfRange(in, 0,i));
root.right = buildTree(Arrays.copyOfRange(pre, i+1, pre.length), Arrays.copyOfRange(in, i+1, in.length));
}
}
return root;
}
求和为指定值的路径个数
注意:不强制要求是从根节点开始
class Solution {
int res = 0;
public int pathSum(TreeNode root, int sum) {
if (root == null) return 0;
//从根出发
help(root, sum, root.val);
//从左子树出发
pathSum(root.left, sum);
//从右子树出发
pathSum(root.right, sum);
return res;
}
private void help (TreeNode root, int target, int sum) {
if (root == null) return;
if (sum == target) {
res++;
}
if (root.left != null) {
help(root.left, target, sum + root.left.val);
}
if (root.right != null) {
help(root.right, target, sum+root.right.val);
}
}
}
求和为指定值的路径集合
注意:要求从根节点到叶子节点
思路:回溯三步骤
1. 确定递归结束条件,当前节点为null
2. 确定处理逻辑。 如果是叶子节点并且余数=0 则放入结果集合中 否则递归左右子树 进行回溯
3. 确定方法参数。参数一:当前节点 参数二:余数
class Solution {
List<List<Integer>> res = new LinkedList();
Stack<Integer> path = new Stack();
public List<List<Integer>> pathSum(TreeNode root, int sum) {
help(root, sum);
return res;
}
private void help(TreeNode root, int sum) {
if (root == null) return;
sum -= root.val;
path.push(root.val);
//和满足条件 并且 是叶子结点
if (sum == 0 && root.left == null && root.right == null) {
res.add(new LinkedList(path));
}
//递归左右子树
help(root.left, sum);
help(root.right, sum);
//回溯
path.pop();
}
}
求是否存在从根到叶子节点路径和等于指定的值
public boolean hasPathSum(TreeNode root, int sum) {
if (root == null) return false;
Stack<TreeNode> nodeStack = new Stack();
Stack<Integer> sumStack = new Stack();
nodeStack.push(root);
sumStack.push(sum);
while (!nodeStack.isEmpty()) {
TreeNode node = nodeStack.pop();
int tmp = sumStack.pop();
if (node.left == null && node.right == null && (tmp-node.val) == 0) {
return true;
}
if (node.left != null) {
nodeStack.push(node.left);
sumStack.push(tmp-node.val);
}
if (node.right != null) {
nodeStack.push(node.right);
sumStack.push(tmp-node.val);
}
}
return false;
}
二叉搜索树返回指定节点的后继节点
public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
if (root == null) return null;
if (p.val >= root.val) {
return inorderSuccessor(root.right, p);
}else {
TreeNode node = inorderSuccessor(root.left, p);
//不等于null 则返回右子树的最左节点
//等于null 则说明当前节点的左节点为null 返回当前节点
return node == null ? root : node;
}
}
中序遍历的下一个节点
private static Integer getNext(TreeNode tree) {
// TODO Auto-generated method stub
// 如果有右孩子,则下一个节点是右孩子中最左子节点
TreeNode temp;
if (tree.right != null) {
temp = tree.right;
while (temp.left != null) {
temp = temp.left;
}
return temp.val;
}
// 节点是其父节点的左子节点,则下一个节点就是父节点(节点没有右孩子)
if (tree.father != null && tree.father.left == tree) {
return tree.father.val;
}
// 如果节点是父节点的右子节点(节点没有右孩子),下一个节点:父节点是其父节点的左孩子
if (tree.father != null && tree.father.right == tree) {
temp = tree.father;
while (temp != null) {
if (temp.father.left == temp) {
return temp.father.val;
}
temp = temp.father;
}
// 最后没找到的话 就说明这是最后一个,不存在他的下一个了
}
return null;
}
合法二叉搜索树
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
Stack<TreeNode> stack = new Stack();
double tmp = -Double.MAX_VALUE;
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root. left;
}
root = stack.pop();
if (root.val <= tmp) {
return false;
}
tmp = root.val;
root = root.right;
}
return true;
}
树中每行的最大值
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
int max = Integer.MIN_VALUE;
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
max = Math.max(max, node.val);
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
res.add(max);
}
return res;
}
最近公共祖先
public TreeNode lowest(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) return root;
TreeNode left = lowest(root.left, p, q);
TreeNode right = lowest(root.right, p, q);
if (left != null && right != null) return root;
return left == null ? right : left;
}
二叉搜索树的第k小的元素
public int kthSmallest(TreeNode root, int k) {
Stack<TreeNode> stack = new Stack();
while (true) {
while(root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
if (--k == 0) return root.val;
root = root.right;
}
}
每层节点所构成的链表集合
ArrayList<ListNode> res = new ArrayList();
public ListNode[] listOfDepth(TreeNode tree) {
if (tree == null) return new ListNode[0];
help(tree);
return res.toArray(ListNode[]::new);
}
private void help(TreeNode root) {
if (root == null) return;
Queue<TreeNode> queue = new LinkedList();
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
ListNode node = new ListNode(-1);
ListNode cur = node;
for (int i = 0; i < size; i++) {
TreeNode tmp = queue.poll();
cur.next = new ListNode(tmp.val);
cur = cur.next;
if (tmp.left != null) {
queue.add(tmp.left);
}
if (tmp.right != null) {
queue.add(tmp.right);
}
}
if (node.next != null) {
res.add(node.next);
}
}
}
判断是否是平衡二叉树
class Solution {
public boolean isBalanced(TreeNode root) {
if (root == null) return true;
return help(root) != -1;
}
private int help(TreeNode root) {
if (root == null) return 0;
//判断左子树是否平衡
int left = help(root.left);
//不平衡则提前结束(剪枝)
if (left == -1) return -1;
int right = help(root.right);
if (right == -1) return -1;
//左右子树各自平衡, 判断左右子树是否平衡, 不平衡返回-1, 平衡返回高度
return Math.abs(left-right) < 2 ? Math.max(left,right)+1 : -1;
}
//时间复杂度为 O(n) 每个节点遍历1遍
}
二叉搜索树的最近公共祖先
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while(root != null) {
if (p.val < root.val && q.val < root.val) {
root = root.left;
}else if (p.val > root.val && q.val > root.val) {
root = root.right;
}else {
break;
}
}
return root;
}
二叉搜索树的第k大节点
int res = 0, k = 0;
public int kthLargest(TreeNode root, int k) {
this.k = k;
help(root);
return res;
}
private void help(TreeNode root) {
if (root == null) return;
//找中序遍历的倒序 (右 根 左) 第k个节点
help(root.right);
if (--k == 0) {
res = root.val;
return;
}
help(root.left);
}