Skip to content

Latest commit

 

History

History
763 lines (619 loc) · 19.9 KB

File metadata and controls

763 lines (619 loc) · 19.9 KB

1、重建二叉树

重建二叉树

public TreeNode reConstructBinaryTree(int [] pre, int [] in) {
    return reConstructBinaryTree(pre,in,0,pre.length-1,0,in.length-1);
}

private TreeNode reConstructBinaryTree(int[] pre,int[] in,
                                       int preStart,int preEnd,
                                       int inStart,int inEnd){
    if(preStart>preEnd || inStart>inEnd){
        return null;
    }
    TreeNode root = new TreeNode(pre[preStart]);

    int index = -1;
    for(int i=inStart;i<=inEnd;i++){
        if(in[i]==pre[preStart]){
            index = i;
            break;
        }
    }
    root.left = reConstructBinaryTree(pre,in,
                                      preStart+1,preStart+(index-inStart),inStart,index-1);
    root.right = reConstructBinaryTree(pre,in,
                                       preStart+(index-inStart)+1,preEnd,index+1,inEnd);
    return root;
}

2、二叉树的下一个结点

二叉树的下一个结点

//思路:
//1、如果一个节点的右子树不为空,那么该节点的下一个节点是右子树的最左节点;
//否则,向上找第一个左链接指向的树包含该节点的祖先节点。
public TreeLinkNode GetNext(TreeLinkNode pNode){
    if(pNode==null){
        return null;
    }
    if(pNode.right!=null){
        //先判断 pNode 的右子树不为 null,
        //pNode 的下一个结点就是 pNode 右子树的最左结点
        TreeLinkNode node = pNode.right; //pNode 的右子树
        while(node.left!=null){
            node = node.left;
        }
        return node;
    }else{   //否则,向上找第一个左连接指向的树包含该节点的祖先节点
        while (pNode.next!=null){
            TreeLinkNode parent = pNode.next;
            if(parent.left==pNode){
                return parent;
            }
            pNode = pNode.next;
        }
    }
    return null;
}

3、对称的二叉树

对称的二叉树

boolean isSymmetrical(TreeNode pRoot) {
    if(pRoot==null){
        return true;
    }
    return isSymmetrical(pRoot.left,pRoot.right);
}

//判断 p 和 q 两棵树是否对称
private boolean isSymmetrical(TreeNode p,TreeNode q){
    if(p==null && q==null){
        return true;
    }
    if(p==null || q==null){
        return false;
    }
    if(p.val!=q.val){
        return false;
    }
    return isSymmetrical(p.left,q.right) &&
        isSymmetrical(p.right,q.left);
}

4、按之字形顺序打印二叉树

按之字形顺序打印二叉树

public ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
    ArrayList<ArrayList<Integer>> res = new ArrayList<>();
    if(pRoot==null){
        return res;
    }

    //queue 存储的是每一行的结点
    Queue<TreeNode> queue = new LinkedList<>();
    queue.add(pRoot);

    int level = 0;

    while(!queue.isEmpty()){
        if(level==res.size()){
            res.add(new ArrayList<>());
        }
        int num = queue.size();
        while(num-->0) {
            TreeNode node = queue.poll();
            res.get(level).add(node.val);
            if(node.left!=null){
                queue.add(node.left);
            }
            if(node.right!=null){
                queue.add(node.right);
            }
        }
        if(level%2==1){
            Collections.reverse(res.get(level));
        }
        level++;
    }

    return res;
}

*5、把二叉树打印成多行

把二叉树打印成多行

ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
    ArrayList<ArrayList<Integer>> res = new ArrayList<>();
    if(pRoot==null){
        return res;
    }

    Queue<TreeNode> queue = new LinkedList<>();
    queue.add(pRoot);

    int level=0;

    while(!queue.isEmpty()){
        if(level==res.size()){
            res.add(new ArrayList<>());
        }
        int num = queue.size();
        while (num-->0){
            TreeNode node = queue.poll();
            res.get(level).add(node.val);
            if(node.left!=null){
                queue.add(node.left);
            }
            if(node.right!=null){
                queue.add(node.right);
            }
        }
        level++;
    }
    return res;
}

*6、序列化二叉树

序列化二叉树

String Serialize(TreeNode root) {
    if(root==null){
        return "#";
    }
    return root.val+" "+Serialize(root.left)+" "+Serialize(root.right);
}

//反序列化:将字符串转化为二叉树
//注意 " " 和 "#"

private String deserializeStr;

TreeNode Deserialize(String str) {
    deserializeStr=str;
    return Deserialize();
}

private TreeNode Deserialize(){
    if (deserializeStr.length() == 0)
        return null;
    int index = deserializeStr.indexOf(" ");
    
    //TODO:
    //如果 index==-1 ,说明 deserializeStr 中没有出现" ",deserializeStr 表示一个节点的值
    //如果 index=!-1,说明 deserializeStr[0,index-1] 是节点值
    String node = index==-1?deserializeStr:deserializeStr.substring(0, index);
    deserializeStr = index == -1 ? "" : deserializeStr.substring(index + 1); 
    //从 " "的下一个位置开始
    if("#".equals(node)){
        return null;
    }
    int val = Integer.parseInt(node);
    TreeNode root = new TreeNode(val);
    root.left =Deserialize();
    root.right=Deserialize();
    return root;
}

*7、树的子结构

树的子结构

public boolean HasSubtree(TreeNode root1, TreeNode root2) {
    if(root1==null || root2==null){  //注意:这里约定空树不是任意一个树的子结构
        return false;
    }
    return HasSubtree(root1.left,root2) ||
        isSubtree(root1,root2) ||
        HasSubtree(root1.right,root2);
}

//判断以 root2 为根节点的树是否是以 root1 为根节点的子树。
//比如:
//   2
//  /
// 4 
// 是
//   2
//  / \
// 4   5
// 的子树
private boolean isSubtree(TreeNode root1,TreeNode root2){
    if(root2==null){ // root2 为空树是 root1 的子树
        return true;
    }
    if(root1==null){ //显然空树没有子树
        return false;
    }
    if(root1.val!=root2.val){
        return false;
    }
    return isSubtree(root1.left,root2.left) &&
        isSubtree(root1.right,root2.right);
}

8、从上往下打印二叉树

从上往下打印二叉树

public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
    ArrayList<Integer> res = new ArrayList<>();
    if(root==null){
        return res;
    }

    Queue<TreeNode> queue = new LinkedList<>();
    queue.add(root);

    while (!queue.isEmpty()){
        int num = queue.size();
        while(num-->0){
            TreeNode node = queue.poll();
            res.add(node.val);
            if(node.left!=null){
                queue.add(node.left);
            }
            if(node.right!=null){
                queue.add(node.right);
            }
        }
    }
    return res;
}

9、二叉树的深度

二叉树的深度

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

10、二叉树的最小深度

二叉树的最小深度

public int minDepth(TreeNode root) {
    if(root==null){
        return 0;
    }

    //   1
    //  /
    // 2     
    //最小深度是 1
    if(root.right==null){
        return 1+minDepth(root.left);
    }
    //  1
    //   \
    //    2
    //的最小深度是 1
    if(root.left==null){
        return 1+minDepth(root.right);
    }
    return Math.min(minDepth(root.left),minDepth(root.right))+1;
}

11、合并二叉树

合并二叉树

public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
    if(t1==null){
        return t2;
    }
    if(t2==null){
        return t1;
    }
    TreeNode root=new TreeNode(t1.val+t2.val);
    root.left=mergeTrees(t1.left,t2.left);
    root.right=mergeTrees(t1.right,t2.right);
    return root;
}

*12、二叉树的所有路径

二叉树的所有路径

public List<String> binaryTreePaths(TreeNode root) {
    List<String> paths=new ArrayList<>();
    if(root==null){
        return paths;
    }
    List<Integer> values=new ArrayList<>();
    backtrack(root,values,paths);
    return paths;
}

//values 记录从根节点到叶子节点
//paths 记录路径
private void backtrack(TreeNode root, List<Integer> values,List<String> paths){
    if(root==null){
        return;
    }
    values.add(root.val);
    if(root.left==null && root.right==null){ // 到达叶子节点
        paths.add(buildPath(values));
    }else{
        backtrack(root.left,values,paths);
        backtrack(root.right,values,paths);
    }
    values.remove(values.size()-1);
}

private String buildPath(List<Integer> values){
    StringBuilder res=new StringBuilder();
    for(int i=0;i<values.size();i++){
        if(i==values.size()-1){
            res.append(values.get(i));
        }else{
            res.append(values.get(i)).append("->");
        }
    }
    return res.toString();
}

13、二叉树中和为某一值的路径(39)

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

public ArrayList<ArrayList<Integer>> FindPath(TreeNode root, int target) {
    ArrayList<ArrayList<Integer>> res = new ArrayList<>();
    ArrayList<Integer> values = new ArrayList<>();
    backtrack(root,target,values,res);
    return res;
}

// values : 记录从根节点到叶子节点的所有路径
// paths : 存储所有可能的结果
private void backtrack(TreeNode root, int target,
                       ArrayList<Integer> values,
                       ArrayList<ArrayList<Integer>> paths) {
    if (root == null) {
        return;
    }
    values.add(root.val);
    if(root.left==null && root.right==null && root.val==target){
        paths.add(new ArrayList<>(values));
    }else{
        backtrack(root.left,target-root.val,values,paths);
        backtrack(root.right,target-root.val,values,paths);
    }
    values.remove(values.size()-1);
}

14、二叉树的镜像

二叉树的镜像

public void Mirror(TreeNode root) {
    if(root==null){
        return;
    }
    swap(root);
    Mirror(root.left);
    Mirror(root.right);
}

//交换 root 的左右子树
private void swap(TreeNode root){
    TreeNode tmp = root.left;
    root.left = root.right;
    root.right = tmp;
}

*15、平衡二叉树

平衡二叉树

private boolean isBalanced=true;

public boolean isBalanced(TreeNode root) {
    if(root==null){
        return true;
    }
    height(root);
    return isBalanced;
}

private int height(TreeNode root){
    if(root==null){
        return 0;
    }
    int left=height(root.left);
    int right=height(root.right);
    if(Math.abs(left-right)>1){
        isBalanced=false;
    }
    return 1+Math.max(left,right);
}

*16、二叉树的最近公共祖先

二叉树的最近公共祖先

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    // p ,q 都在左子树
    if(contains(root.left,p) && contains(root.left,q)){
        return lowestCommonAncestor(root.left,p,q);
    }
    // p,q 都在右子树
    if(contains(root.right,p) && contains(root.right,q)){
        return lowestCommonAncestor(root.right,p,q);
    }
    return root;
}

//判断以root 为根节点二叉树是否包含 p 节点
private boolean contains(TreeNode root,TreeNode p){
    if(root==null || p==null){
        return false;
    }
    if(root.val == p.val){
        return true;
    }
    return contains(root.left,p) || contains(root.right,p);
}
//思路二: 
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    if(root == null){
        return null;
    }
    //如果 p或者是q是根节点,那么该root就是他们最近的公共父节点
    if(p== root || q==root){
        return root;
    }
    
    //   1
    //  / \
    // 2   3
    // 其中 p 为 2,q 为 3 则 left=p,right=q
    //显然 root 为 p、q 的最近公共祖先
    //p,q 在左子树中是否有公共父节点
    TreeNode left = lowestCommonAncestor(root.left,p,q);
    //p,q 在右子树中是否有公共父节点
    TreeNode right = lowestCommonAncestor(root.right,p,q);
    if(left!=null && right!=null){
        return root;
    }
    if(left != null){
        return left;
    }
    if(right != null){
        return right;
    }
    return null;
}

17、二叉搜索树的最近公共祖先

二叉搜索树的最近公共祖先

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    if(root==null){
        return null;
    }
    if(p.val<root.val && q.val<root.val){
        return lowestCommonAncestor(root.left,p,q);
    }
    if(p.val>root.val && q.val>root.val){
        return lowestCommonAncestor(root.right,p,q);
    }
    return root;
}

18、二叉搜索树的第 k 个结点(17)

二叉搜索树的第 k 个结点

//思路:
//利用二次搜索树的中序遍历性质

private TreeNode res;
private int cnt;

TreeNode KthNode(TreeNode pRoot, int k) {
    if(pRoot==null){
        return null;
    }
    inOrder(pRoot,k);
    return res;
}

private void inOrder(TreeNode pRoot,int k){
    if(pRoot==null){
        return;
    }
    inOrder(pRoot.left,k);
    cnt++;
    if(cnt==k){
        res = pRoot;
        return;
    }
    inOrder(pRoot.right,k);
}

*19、二叉搜索树的后序遍历序列

二叉搜索树的后序遍历序列

//思路一:
//先假设该后续遍历序列可以构成二叉树
//对题目中后序遍历序列进行排序即可获取中序遍历序列
//然后根据中序遍历序列和后序遍历序列构造二叉树
//如果构造失败,返回 false
//如果构造成功,返回 true

public boolean VerifySquenceOfBST(int [] sequence) {
    if(sequence==null || sequence.length==0){
        return false;
    }
    int[] post = Arrays.copyOf(sequence,sequence.length);
    Arrays.sort(sequence);

    TreeNode root = null;
    try{
        root = reConstrcut(sequence,post,
                           0,sequence.length-1,0,post.length-1);
    }catch (Exception e){ //构造过程中,发生异常,即构造失败
        return false;
    }
    //root==null 也是构造失败
    return root!=null;
}

private TreeNode reConstrcut(int[] in,int[] post,
                             int inStart,int inEnd,int postStart,int postEnd){
    if(inStart>inEnd || postStart>postEnd){
        return null;
    }
    TreeNode root = new TreeNode(post[postEnd]);
    int index=-1;
    for(int i=inStart;i<=inEnd;i++){
        if(in[i]==post[postEnd]){
            index=i;
            break;
        }
    }
    root.left = reConstrcut(in,post,inStart,index-1,
                            postStart,postStart+(index-inStart-1));
    root.right=reConstrcut(in,post,index+1,inEnd,
                           postStart+(index-inStart),postEnd-1);
    return root;
}
//思路二:
//利用二分搜索树性质
//将 sequence 划分为左右子树序列
//如果能构成二分搜索树
//左子树中的数值 <= 根节点值
//右子树中的数值 > 根节点值

public boolean VerifySquenceOfBST(int [] sequence) {
    if(sequence==null || sequence.length==0){
        return false;
    }
    return verify(sequence,0,sequence.length-1);
}

private boolean verify(int[] squence,int first,int last){
    if(last-first<=1){
        //当 last-first==0 时,只有 1 个结点,显然正确
        //当 last-first==1 时,只有 2 个结点,此时不管是顺序的还是逆序的都可以构造
        return true;
    }
    int rootVal = squence[last]; //后序遍历最后一个元素值就是根节点的值
    int cutIndex = first; // cutIndex 用于切分左右子树
    while (cutIndex<last && squence[cutIndex]<=rootVal){ //二分搜索树中左子树所有结点值都小于根节点值
        cutIndex++;
    }
    //左子树 [first,curIndex-1]
    //cutIndex 就是右子树的后序遍历的首元素的下标 
    for(int i=cutIndex;i<last;i++){ //右子树[curIndex,last-1]
        if(rootVal>squence[i]){ //右子树中存在大于根节点的值,返回 false
            return false;
        }
    }
    return verify(squence,first,cutIndex-1) &&
        verify(squence,cutIndex,last-1);
}

*20、二叉搜索树与双向链表

二叉搜索树与双向链表

//思路:
//二分搜索树有序:中序遍历
//难点在于不能创建任何新节点

private TreeNode pre = null; //指向当前节点的前一个节点
private TreeNode head = null; //指向头节点

public TreeNode Convert(TreeNode pRootOfTree) {
    if(pRootOfTree==null){
        return null;
    }
    inOrder(pRootOfTree);
    return head;
}

// node 是当前节点
private void inOrder(TreeNode node){
    if(node==null){
        return;
    }
    inOrder(node.left);
    node.left = pre;
    if(pre!=null){ //说明 root 不是头结点
        pre.right=node;
    }
    pre=node;
    if(head==null){
        head = node;
    }
    inOrder(node.right);
}