目录
1、100. 相同的树 - 力扣(LeetCode)
2、572. 另一棵树的子树 - 力扣(LeetCode)
3、110. 平衡二叉树 - 力扣(LeetCode)
4、101. 对称二叉树 - 力扣(LeetCode)
5、102. 二叉树的层序遍历 - 力扣(LeetCode)
6、判断该树是否为完全二叉树
七、二叉树遍历_牛客题霸_牛客网 (nowcoder.com)
八、236. 二叉树的最近公共祖先 - 力扣(LeetCode)
九、二叉搜索树与双向链表_牛客题霸_牛客网 (nowcoder.com)
十、105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)
十一、106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
十二、非递归实现二叉树的前中后序遍历
我们考虑它相同和不相同的情况,再用递归遍历:
完整代码:
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q != null || p != null && q == null){
return false;
}
if (p == null && q == null){
return true;
}
if(p.val != q.val){
return false;
}
return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
}
这道题,我们可以直接用上一道题的代码,其思路如下:
完整代码:
class Solution {
//时间复杂度为:n * m
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q != null || p != null && q == null) {
return false;
}
if(p == null && q == null) {
return true;
}
if(p.val != q.val) {
return false;
}
return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
}
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if (root == null || subRoot == null){
return false;
}
if (isSameTree(root,subRoot)){
return true;
}
if(isSubtree(root.left,subRoot)){
return true;
}
if(isSubtree(root.right,subRoot)){
return true;
}
return false;
}
}
思路:
完整代码:
class Solution {
//时间复杂度为:n * n
int getHeight(TreeNode root){
if (root == null){
return 0;
}
int leftTree = getHeight(root.left);
int rightTree = getHeight(root.right);
return leftTree > rightTree ? leftTree+1 : rightTree+1;
}
public boolean isBalanced(TreeNode root) {
if(root == null){
return true;
}
int leftHeight = getHeight(root.left);
int rightHeight = getHeight(root.right);
return Math.abs(leftHeight-rightHeight) <= 1
&& isBalanced(root.left)
&& isBalanced(root.right);
}
}
上面的这种解法的时间复杂度是O(n^2),会出现大量的的重复计算,当计算根结点的左子树高度时,递归到数字九时返回一个2就已经说明了该树不平衡,所以我们从下向上计算高度时顺便判断一下,这样的话时间复杂度就是O(n):
class Solution {
int getHeight(TreeNode root){
if (root == null){
return 0;
}
int leftHeight = getHeight(root.left);
int rightHeight = getHeight(root.right);
if(leftHeight >= 0 && rightHeight >= 0 && Math.abs(leftHeight - rightHeight) <= 1){
return Math.max(leftHeight,rightHeight) + 1;
}else{
//返回-1 就说明已经出现了不平衡
return -1;
}
}
public boolean isBalanced(TreeNode root) {
if(root == null){
return true;
}
return getHeight(root) >= 0;
}
}
思路就是判断root的左右子树是否对称:左子树的右树和右子树的左树是否相同:
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) {
return true;
}
return isSymmetricChild(root.left,root.right);
}
private boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree) {
//判断左子树的右树和右子树的左树是否相同.
if (leftTree == null && rightTree != null || leftTree != null && rightTree == null){
return false;
}
//是否都为空
if (leftTree == null && rightTree == null){
return true;
}
//判断val值
if (leftTree.val != rightTree.val){
return false;
}
//进行递归左子树的右树和右子树的左树
return isSymmetricChild(leftTree.left, rightTree.right) &&
isSymmetricChild(leftTree.right, rightTree.left);
}
}
思路:
完整代码:
class Solution {
public List> levelOrder(TreeNode root) {
List> ret = new ArrayList>();
if(root == null){
return ret;
}
Queue queue = new LinkedList();
queue.offer(root);
while(!queue.isEmpty()){
List leve = new ArrayList();
int queue_size = queue.size();
for(int i = 0; i < queue_size; i++){
TreeNode node = queue.poll();
leve.add(node.val);
if(node.left != null){
queue.offer(node.left);
}
if(node.right != null){
queue.offer(node.right);
}
}
ret.add(leve);
}
return ret;
}
}
思路:
完整代码:
boolean isCompleteTree(TreeNode root){
if (root == null){
return true;
}
Queue queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
TreeNode cur = queue.poll();
if (cur != null){
queue.offer(cur.left);
queue.offer(cur.right);
}else {
break;
}
}
while (!queue.isEmpty()){
TreeNode cur = queue.peek();
if (cur != null){
//不是完全二叉树
return false;
}else {
queue.poll();
}
}
return true;
}
import java.util.*;
public class Main {
class TreeNode{
public char val;
public TreeNode left;
public TreeNode right;
public TreeNode(char val){
this.val = val;
}
}
public int i = 0;
//创建树
public TreeNode createTree(String s){
TreeNode root = null;
if (s.charAt(i) != '#'){
root = new TreeNode(s.charAt(i));
i++;
root.left = createTree(s);
root.right = createTree(s);
}else {
i++;
}
return root;
}
public void inorder(TreeNode root){
if (root == null){
return;
}
inorder(root.left);
System.out.print(root.val+" ");
inorder(root.right);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
String s = scanner.nextLine();
Main m = new Main();
TreeNode root = m.createTree(s);
m.inorder(root);
}
}
}
先列出求公共祖先会出现的情况:
分析:
完整代码:
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
if(root == null){
return null;
}
if(root == p || root == q){
return root;
}
TreeNode retleft = lowestCommonAncestor(root.left,p,q);
TreeNode retright = lowestCommonAncestor(root.right,p,q);
if(retleft != null && retright != null){
return root;
}else if(retleft != null){//都在左树
return retleft;
}else{
return retright;
}
}
}
当我们用栈的思想来解决这道题时,可以有:
完整代码:
class Solution {
//找到根结点到指定节点node之间路径上的所有结点,存储到栈中
private boolean getPath(TreeNode root, TreeNode node, Stack stack) {
if (root == null || node == null) {
return false;
}
stack.push(root);
if (root == node) {
return true;
}
boolean ret1 = getPath(root.left, node, stack);
if (ret1) {
return true;
}
boolean ret2 = getPath(root.right, node, stack);
if (ret2) {
return true;
}
//当前根结点不是,根的左右子树都不是
stack.pop();
return false;
}
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
Stack stack1 = new Stack<>();
getPath(root,p,stack1);
Stack stack2 = new Stack<>();
getPath(root,q,stack2);
int size1 = stack1.size();
int size2 = stack2.size();
if(size1 > size2){
int tmp = size1 - size2;
while(tmp != 0){
stack1.pop();
tmp--;
}
}else{
int tmp = size2 - size1;
while(tmp != 0){
stack2.pop();
tmp--;
}
}
while(!stack1.empty() && !stack2.empty()){
if(stack1.peek() == stack2.peek()){
return stack1.peek();
}else{
stack1.pop();
stack2.pop();
}
}
return null;
}
}
思路:
public class Solution {
TreeNode prev = null;
public void ConvertChild(TreeNode root){
if (root == null){
return;
}
ConvertChild(root.left);
root.left = prev;
if (prev != null){
prev.right = root;
}
prev = root;
ConvertChild(root.right);
}
public TreeNode Convert(TreeNode pRootOfTree){
if (pRootOfTree == null){
return null;
}
ConvertChild(pRootOfTree);
TreeNode head = pRootOfTree;
while(head.left != null){
head = head.left;
}
return head;
}
}
思路:
完整代码:
class Solution {
public int preIndex = 0;
public TreeNode buildTreeChild(int[] preorder, int[] inorder,int inBegin,int inEnd){
if(inBegin > inEnd){
return null;
}
TreeNode root = new TreeNode(preorder[preIndex]);
int rootIndex = findInorderIndex(inorder,preorder[preIndex],inBegin,inEnd);
preIndex++;
root.left = buildTreeChild(preorder,inorder, inBegin, rootIndex-1);
root.right = buildTreeChild(preorder,inorder,rootIndex+1, inEnd);
return root;
}
//找到根结点的位置
private int findInorderIndex(int[] inorder,int val,int inBegin,int inEnd){
for(int i = inBegin; i <= inEnd; i++){
if(inorder[i] == val){
return i;
}
}
return -1;
}
public TreeNode buildTree(int[] preorder, int[] inorder) {
return buildTreeChild(preorder,inorder,0,inorder.length-1);
}
}
同理这道题也是一样的道理:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
只不过变成了后序序列倒着是根结点:
class Solution {
public int postIndex;
public TreeNode buildTreeChild(int[] postorder, int[] inorder,int inBegin,int inEnd){
if(inBegin > inEnd){
return null;
}
TreeNode root = new TreeNode(postorder[postIndex]);
int rootIndex = findInorderIndex(inorder,postorder[postIndex],inBegin,inEnd);
postIndex--;
root.right = buildTreeChild(postorder,inorder,rootIndex+1, inEnd);
root.left = buildTreeChild(postorder,inorder, inBegin, rootIndex-1);
return root;
}
private int findInorderIndex(int[] inorder,int val,int inBegin,int inEnd){
for(int i = inBegin; i <= inEnd; i++){
if(inorder[i] == val){
return i;
}
}
return -1;
}
public TreeNode buildTree(int[] inorder,int[] postorder) {
postIndex = postorder.length-1;
return buildTreeChild(postorder,inorder,0,inorder.length-1);
}
}
思路:
每颗小子树走完都会加一个右括号,当然除了根结点剩下的结点都先加一个左括号,变美丽树,并将其打印出来:
class Solution {
public String tree2str(TreeNode root) {
//通过StringBuilder修改字符串
StringBuilder sb = new StringBuilder();
tree2strChild(root,sb);
return sb.toString();
}
private void tree2strChild(TreeNode t,StringBuilder sb){
if(t == null){
return;
}
sb.append(t.val);
//左子树不为空就加个左括号
if(t.left != null){
sb.append("(");
tree2strChild(t.left,sb);
sb.append(")");
}else{
if(t.right == null){
return;
}else{
sb.append("()");
}
}
if(t.right == null){
return;
}else{
sb.append("(");
tree2strChild(t.right,sb);
sb.append(")");
}
}
}
前序遍历思路:
创建一个栈,将根结点入栈并打印,再遍历root.left,当结点左右子树为空时就出栈并赋值给top记录下来,再继续遍历root.right:
class Solution {
public List preorderTraversal(TreeNode root){
List ret = new ArrayList<>();
Stack stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
System.out.println(cur.val + " ");
ret.add(cur.val);
cur = cur.left;
}
TreeNode top = stack.pop();
cur = top.right;
}
return ret;
}
}
中序遍历同理:
class Solution {
public List inorderTraversal(TreeNode root) {
List list = new ArrayList<>();
Stack stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
TreeNode top = stack.pop();
System.out.println(cur.val + " ");
list.add(top.val);
cur = top.right;
}
return list;
}
}
后序遍历:
class Solution {
public List postorderTraversal(TreeNode root) {
List list = new ArrayList<>();
Stack stack = new Stack<>();
TreeNode prev = null;
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
//不能直接弹出
TreeNode top = stack.peek();
if(top.right == null || top.right == prev){
stack.pop();
list.add(top.val);
prev = top;
}else{
cur = top.right;
}
}
return list;
}
}