算法题--二叉树

221 阅读6分钟

算法框架:

void traverse(TreeNode root) { 
    // 前序遍历 
       traverse(root.left)
    // 中序遍历 
       traverse(root.right) 
    // 后序遍历 
}

1.重建二叉树

用到java的Arrays.copyOfRange()方法

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
import java.util.Arrays;
public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        if(pre.length==0||in.length==0){
            return null;
        }
        TreeNode root=new TreeNode(pre[0]);
        for(int i=0;i<in.length;i++){
            if(pre[0]==in[i]){
            //每次都找子树的左和右
                root.left=reConstructBinaryTree(Arrays.copyOfRange(pre,1,i+1),Arrays.copyOfRange(in,0,i));
                root.right=reConstructBinaryTree(Arrays.copyOfRange(pre,i+1,pre.length),Arrays.copyOfRange(in,i+1,in.length));
                break;
            }
            continue;
        }
        return root;
    }
}

2.树的子结构

链接:https://www.nowcoder.com/questionTerminal/6e196c44c7004d15b1610b9afca8bd88?answerType=1&f=discussion
来源:牛客网

public class Solution {
 
    public boolean jude(TreeNode node, TreeNode no) { // 第二步
        if (no == null) {
            return true;
        }
        if (node == null) {
            return false;
        }
 
        if (node.val == no.val) {
            return jude(node.left, no.left) && jude(node.right, no.right);
        } else {
            return false;
        }
    }
 
    public boolean HasSubtree(TreeNode root1, TreeNode root2) { // 第一步 深度遍历
        if (root1 == null || root2 == null) {
            return false;
        }
        return jude(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2);
    }
}

3.二叉树的镜像

非递归实现

链接:https://www.nowcoder.com/questionTerminal/564f4c26aa584921bc75623e48ca3011?answerType=1&f=discussion
来源:牛客网

public void Mirror(TreeNode root) {
        if(root == null) return;
        Queue<TreeNode> nodes = new LinkedList<>();
        TreeNode curr, temp;
        nodes.offer(root);
        while(!nodes.isEmpty()){
            int len = nodes.size();
            for(int i = 0; i < len; i++){
                curr = nodes.poll();
                temp = curr.left;
                curr.left = curr.right;
                curr.right = temp;
                if(curr.left != null) nodes.offer(curr.left);
                if(curr.right != null) nodes.offer(curr.right);
            }
        }
    }

4.二叉树的后序遍历序列

链接:https://www.nowcoder.com/questionTerminal/a861533d45854474ac791d90e447bafd?answerType=1&f=discussion
来源:牛客网

public class Solution {
 
    public boolean helpVerify(int [] sequence, int start, int root){
        if(start >= root)return true;
        int key = sequence[root];
        int i;
        //找到左右子数的分界点
        for(i=start; i < root; i++)
            if(sequence[i] > key)
                break;
        //在右子树中判断是否含有小于root的值,如果有返回false
        for(int j = i; j < root; j++)
            if(sequence[j] < key)
                return false;
        return helpVerify(sequence, start, i-1) && helpVerify(sequence, i, root-1);
    }
    public boolean VerifySquenceOfBST(int [] sequence) {
        if(sequence == null || sequence.length == 0)return false;
        return  helpVerify(sequence, 0, sequence.length-1);
 
    }
}

5.打印二叉树

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {

vector<int> res;
        if(root==NULL)
            return res;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty()){
            res.push_back(q.front()->val);
            if(q.front()->left!=NULL)
                q.push(q.front()->left);
            if(q.front()->right!=NULL)
                q.push(q.front()->right);
            q.pop();
        }
        return res;
    }
};

6.二叉树中和为某一值的路径

链接:https://www.nowcoder.com/questionTerminal/b736e784e3e34731af99065031301bca?answerType=1&f=discussion
来源:牛客网

public class Solution {
    private ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
    private ArrayList<Integer> list = new ArrayList<>();
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
        if(root == null)return result;
        list.add(root.val);
        target -= root.val;
        if(target == 0 && root.left == null && root.right == null)
            result.add(new ArrayList<Integer>(list));
//因为在每一次的递归中,我们使用的是相同的result引用,所以其实左右子树递归得到的结果我们不需要关心,
//可以简写为FindPath(root.left, target);FindPath(root.right, target);
//但是为了大家能够看清楚递归的真相,此处我还是把递归的形式给大家展现了出来。
        ArrayList<ArrayList<Integer>> result1 = FindPath(root.left, target);
        ArrayList<ArrayList<Integer>> result2 = FindPath(root.right, target);
        list.remove(list.size()-1);
        return result;
    }
}

7.二叉搜索树与双向链表

中序遍历二叉树,然后用一个ArrayList类保存遍历的结果,这样在ArratList中节点就按顺序保存了,然后再来修改指针。

链接:https://www.nowcoder.com/questionTerminal/947f6eb80d944a84850b0538bf0ec3a5?answerType=1&f=discussion
来源:牛客网

public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null){
            return null;
        }
        ArrayList<TreeNode> list = new ArrayList<>();
        Convert(pRootOfTree, list);
        return Convert(list);
 
    }
    //中序遍历,在list中按遍历顺序保存
    public void Convert(TreeNode pRootOfTree, ArrayList<TreeNode> list){
        if(pRootOfTree.left != null){
            Convert(pRootOfTree.left, list);
        }
 
        list.add(pRootOfTree);
 
        if(pRootOfTree.right != null){
            Convert(pRootOfTree.right, list);
        }
    }
    //遍历list,修改指针
    public TreeNode Convert(ArrayList<TreeNode> list){
        for(int i = 0; i < list.size() - 1; i++){
            list.get(i).right = list.get(i + 1);
            list.get(i + 1).left = list.get(i);
        }
        return list.get(0);
    }

8.二叉树的深度

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public int TreeDepth(TreeNode root) {
        if(root==null)return 0;
        int left=TreeDepth(root.left);
        int right=TreeDepth(root.right);
        int result=Math.max(left,right)+1;
        return result;
    }
}

9.平衡二叉树

public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        return deepOftree(root)!=-1;
    }
    int deepOftree(TreeNode root){
        if(root==null)return 0;
        int a=deepOftree(root.left);
        int b=deepOftree(root.right);
        if(a==-1||b==-1||Math.abs(a-b)>1)return -1;
        else return (a>b?a:b)+1;
    }
}

10.二叉树的下一个结点

链接:www.nowcoder.com/questionTer… 来源:牛客网

分析二叉树的下一个节点,一共有以下情况: 1.二叉树为空,则返回空; 2.节点右孩子存在,则设置一个指针从该节点的右孩子出发,一直沿着指向左子结点的指针找到的叶子节点即为下一个节点; 3.节点不是根节点。如果该节点是其父节点的左孩子,则返回父节点;否则继续向上遍历其父节点的父节点,重复之前的判断,返回结果。代码如下:

链接:https://www.nowcoder.com/questionTerminal/9023a0c988684a53960365b889ceaf5e?f=discussion
来源:牛客网

class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        if(pNode==NULL)
            return NULL;
        if(pNode->right!=NULL)
        {
            pNode=pNode->right;
            while(pNode->left!=NULL)
                pNode=pNode->left;
            return pNode;
        }  
        while(pNode->next!=NULL)
        {
            TreeLinkNode *proot=pNode->next;
            if(proot->left==pNode)
                return proot;
            pNode=pNode->next;
        }
        return NULL;
    }
};

11.对称的二叉树

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    boolean isSymmetrical(TreeNode pRoot)
    {
        
        return pRoot==null||judge(pRoot.right,pRoot.left);
    }
    boolean judge(TreeNode right,TreeNode left){
        if(right==null&&left==null)return true;
        if(right==null||left==null)return false;
        if(right.val!=left.val){
            return false;
        }else{
            return judge(right.left,left.right)&&judge(right.right,left.left);
        }
    }
}

12.按之字形顺序打印二叉树

用两个栈分别存奇数行和偶数行,用一个ArrayList<ArrayList >数组存每一行的元素 用while循环 如果是奇数行让s2就按顺序压入左右子节点 反之

链接:https://www.nowcoder.com/questionTerminal/91b69814117f4e8097390d107d2efbe0?f=discussion
来源:牛客网

public static ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
        int layer = 1;
        //s1存奇数层节点
        Stack<TreeNode> s1 = new Stack<TreeNode>();
        s1.push(pRoot);
        //s2存偶数层节点
        Stack<TreeNode> s2 = new Stack<TreeNode>();
         
        ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
         
        while (!s1.empty() || !s2.empty()) {
            if (layer%2 != 0) {
                ArrayList<Integer> temp = new ArrayList<Integer>();
                while (!s1.empty()) {
                    TreeNode node = s1.pop();
                    if(node != null) {
                        temp.add(node.val);
                        System.out.print(node.val + " ");
                        s2.push(node.left);
                        s2.push(node.right);
                    }
                }
                if (!temp.isEmpty()) {
                    list.add(temp);
                    layer++;
                    System.out.println();
                }
            } else {
                ArrayList<Integer> temp = new ArrayList<Integer>();
                while (!s2.empty()) {
                    TreeNode node = s2.pop();
                    if(node != null) {
                        temp.add(node.val);
                        System.out.print(node.val + " ");
                        s1.push(node.right);
                        s1.push(node.left);
                    }
                }
                if (!temp.isEmpty()) {
                    list.add(temp);
                    layer++;
                    System.out.println();
                }
            }
        }
        return list;
    }

13.把二叉树打印成多行

import java.util.ArrayList;
import java.util.Queue;
import java.util.LinkedList;
 

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
//特殊点:按行打印。所以不能普通的bfs,要对每一行的元素存进list里,对一行的元素左右压入队列才能进行下一次的循环
//要学会存数组的头节点进result数组然后返回
//java的queue方法&集合的创建
public class Solution {
    ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer> >result=new ArrayList<>();
        if(pRoot==null)return result;
        Queue<TreeNode> queue=new LinkedList<>();
        ArrayList<Integer>list;
        queue.offer(pRoot);
        while(!queue.isEmpty()){
            list=new ArrayList<>();
            int size=queue.size();
            while(size!=0){
            TreeNode tmp=queue.poll();
            System.out.print(tmp.val+" ");
            list.add(tmp.val);
            if(tmp.left!=null)queue.offer(tmp.left);
            if(tmp.right!=null)queue.offer(tmp.right);
             size--;
            }
            result.add(list);
        }
        return result;
    }
    
}

14.序列化二叉树

链接:https://www.nowcoder.com/questionTerminal/cf7e25aa97c04cc1a68c8f040e71fb84?answerType=1&f=discussion
来源:牛客网

public class SerializeTree {
 
    int index = -1;
    /**
     * 分别遍历左节点和右节点,空使用#代替,节点之间,隔开
     *
     * @param root
     * @return
     */
    public String Serialize(TreeNode root) {
        if (root == null) {
            return "#";
        } else {
            return root.val + "," + Serialize(root.left) + "," + Serialize(root.right);
        }
    }
    /**
     * 使用index来设置树节点的val值,递归遍历左节点和右节点,如果值是#则表示是空节点,直接返回
     *
     * @param str
     * @return
     */
    TreeNode Deserialize(String str) {
        String[] s = str.split(",");//将序列化之后的序列用,分隔符转化为数组
        index++;//索引每次加一
        int len = s.length;
        if (index > len) {
            return null;
        }
        TreeNode treeNode = null;
        if (!s[index].equals("#")) {//不是叶子节点 继续走 是叶子节点出递归
            treeNode = new TreeNode(Integer.parseInt(s[index]));
            treeNode.left = Deserialize(str);
            treeNode.right = Deserialize(str);
        }
        return treeNode;
        }
    }

15.二叉搜索树的第k个结点

中序遍历把元素加进ArrayList即可

链接:https://www.nowcoder.com/questionTerminal/ef068f602dde4d28aab2b210e859150a?answerType=1&f=discussion
来源:牛客网

import java.util.ArrayList;
// {8,6,10,5,7,9,11},8
// null,5
public class Solution {
    ArrayList<TreeNode> list = new ArrayList<>(); // (1)
 
    TreeNode KthNode(TreeNode pRoot, int k)
    {
        addNode(pRoot);
 
        if(k>=1 && list.size()>=k) {
            return list.get(k-1);
        }
 
        return null;
 
    }
 
    // 中序遍历
    void addNode(TreeNode cur) {   // (2)
        if(cur != null) {
            addNode(cur.left);
            list.add(cur);
            addNode(cur.right);
        }
    }
}

二叉树最大路径和

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    
    int ans=Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
        maxcount(root);
        return ans;
    }
    public int maxcount(TreeNode root){
        if(root==null)return 0;
        int left=maxcount(root.left);
        int right=maxcount(root.right);
        //第一种情况
        int lmr=root.val+Math.max(0,right)+Math.max(0,left);
        //第二、三种情况
        int ret=root.val+Math.max(0,Math.max(left,right));
        //每次比较ans、lmr、ret
        ans=Math.max(ans,Math.max(lmr,ret));
        //由于第二、三种情况是要用递归的,所以要返回ret
        return ret;
    }
}