算法-二叉树相关

这篇具有很好参考价值的文章主要介绍了算法-二叉树相关。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

判断二叉树是否是完全二叉树

思路:层次遍历,如果之前某个节点叶子节点为空,队列后续的所有节点的左右节点都不能非空,并且如果节点左节点为null但是右节点不为null该二叉树一定不是满二叉树

public static boolean isCBT1(Node  head) {
        // PC
        if(head == null)
            return true;
        LinkedList<Node > queue = new LinkedList<>();
        boolean isLeaf = false;
        queue.add(head);
        while (!queue.isEmpty()){
            Node  cur = queue.poll();
            Node  left = cur.left;
            Node  right = cur.right;
            if(
                    (isLeaf && (left != null || right != null)) || (left == null && right != null)
            )
                return false;
            if(left != null ){
                queue.add(left);
            }
            if(right != null){
                queue.add(right);
            }
            if(left == null || right == null)
                isLeaf = true;
        }
        return true;
    }

思路2:使用递归方式,返回以当前节点为头结点的二叉树是否是满二叉树|完全二叉树以及返回当前树高度,调用方根据左右子树返回的信息判断当前树是否为完全二叉树

// 使用递归方式
    public static boolean isCBT2(class13.Code01_IsCBT.Node  head) {
        if(head == null)
            return true;
        Info process = process(head);
        return process.isc;

    }
    public static Info process(Node head){
        if (head == null){
            return new Info(true,true,0);
        }
        Info l = process(head.left);
        Info r = process(head.right);
        boolean isFull = l.isf && r.isf && l.height == r.height;
        int height = Math.max(l.height,r.height)+1;
        boolean isComplate = false;
        if(l.height == r.height){
            if((l.isf && r.isf)||(l.isf && r.isc)){
                isComplate = true;
            }
        }else {
            if(l.height == r.height+1){
                if((r.isf && l.isf)||(r.isf && l.isc)){
                    isComplate = true;
                }
            }
        }

        return new Info(isComplate,isFull,height);
    }

    static class Info{
        // 也包括满二叉树场景
        private boolean isc;
        private boolean isf;
        private int height;
        public Info(boolean isc,boolean isf,int height){
            this.isc = isc;
            this.isf = isf;
            this.height = height;
        }
    }

题目:给定一棵二叉树的头节点head,和另外两个节点a和b。返回a和b的最低公共祖先

思路:先序遍历二叉树,过程中记录子节点的父节点,维护在Map类型参数中,然后求第一个相同的祖先

方法2:递归,返回当前节点左右子树是否包含指定节点,如果是直接返回否则根据返回内容处理

static class Info{
        boolean finda;
        boolean findb;
        Node ans ;

        public Info(boolean finda, boolean findb, Node ans) {
            this.finda = finda;
            this.findb = findb;
            this.ans = ans;
        }
    }


    public static Node lowestAncestor1(Node head, Node o1, Node o2) {
        // PC
        Info ans = process(head, o1, o2);
        return ans.ans;

    }
    public  static Info process(Node head, Node o1, Node o2){
        if(head == null)
            return new Info(false,false,null);
        Info l = process(head.left,o1,o2);
        Info r = process(head.right,o1,o2);
        boolean finda = head == o1?true:l.finda||r.finda;
        boolean findb = head == o2?true:r.findb||l.findb;
        Node ans = null;
        if(l.ans != null){
            ans = l.ans;
        }else if (r.ans != null){
            ans = r.ans;
        }else {
            if(finda && findb){
                ans = head;
            }
        }
        return new Info(finda,findb,ans);
    }

题目:派对的最大快乐值 公司的每个员工都符合 Employee 类的描述。整个公司的人员结构可以看作是一棵标准的、 没有环的多叉树。树的头节点是公司唯一的老板。除老板之外的每个员工都有唯一的直接上级。 叶节点是没有任何下属的基层员工(subordinates列表为空),除基层员工外,每个员工都有一个或多个直接下级。派对的最大快乐值这个公司现在要办party,你可以决定哪些员工来,哪些员工不来,规则:1.如果某个员工来了,那么这个员工的所有直接下级都不能来2.派对的整体快乐值是所有到场员工快乐值的累加3.你的目标是让派对的整体快乐值尽量大给定一棵多叉树的头节点boss,请返回派对的最大快乐值。

思路:递归实现


    public static int maxHappy1(Employee boss) {
        // PC
        if(boss == null)
            return 0;
        return Math.max(process(boss,true),process(boss,false));
    }
    // cur 来到当前人员
    // exist 直接领导是否来
    // 返回最大快乐值
    public static  int process(Employee cur,boolean exist){
        if(cur == null)
            return 0;
        // 当前人员选择不来 这种情况和上级领导来或者不来都不影响
        int no = 0;
        for (Employee next : cur.nexts) {
            no += process(next,false);
        }
        int yes = 0;
        // 上级领未来并且当前人员参加
        if(!exist){
            for (Employee next : cur.nexts) {
                yes += process(next,true);
            }
            yes += cur.happy;
        }
        return Math.max(yes,no);
    }

上面递归方式传递参数包含了上级是否参加信息,另外一种递归方式,返回当前人员参加或者不参加两种情况的最大值,由上级决定自己是否参加

static class Info {
        private int no;
        private int yes;

        public Info(int no, int yes) {
            this.no = no;
            this.yes = yes;
        }
    }

    public static int maxHappy2(Employee boss) {
        if (boss == null)
            return 0;
        Info info = process2(boss);
        return Math.max(info.yes, info.no);
    }

    // 返回当前人员参加或者不参加最大happy值
    // 具体如何使用由上层决定
    public static Info process2(Employee cur) {
        if (cur == null)
            return new Info(0, 0);

        int yes = cur.happy;
        int no = 0;
        for (Employee next : cur.nexts) {
            Info info = process2(next);
            no += Math.max(info.no, info.yes);
            yes += info.no;
        }
        return new Info(no, yes);
    }

题目:判断二叉树是否是搜索二叉树

方法1:递归,左右子树返回是否递归相关信息,调用方法根据返回信息判断


    public static boolean isBST1(Node head) {
        if(head == null)
            return true;
        Info info = process(head);
        return info.isSearch;

    }
    // 以当前节点为根节的二叉树,返回是否搜索二叉树信息
    public static Info process(Node head){
        Info left = null;
        if(head.left != null){
            left = process(head.left);
        }
        Info right = null;
        if(head.right != null){
            right = process(head.right);
        }
        int max = head.value;
        int min = head.value;
        if(left != null){
            max = Math.max(max, left.max);
            min = Math.min(min, left.min);
        }
        if(right != null){
            max = Math.max(right.max,max);
            min = Math.min(min, right.min);
        }
        boolean flag = true;

        if(left != null && !left.isSearch)
            flag = false;
        if(right  != null && !right.isSearch)
            flag = false;
        if(left != null && left.max >= head.value)
            flag = false;
        if(right!=null && right.min<= head.value){
            flag = false;
        }

        return new Info(max,min,flag);
    }

    static class Info{
        private int max;
        private int min;
        private boolean isSearch;

        public Info(int max, int min, boolean isSearch) {
            this.max = max;
            this.min = min;
            this.isSearch = isSearch;
        }
    }

方法2:利用二叉搜索树性质,先序遍历一定是递增序列

题目:给定一棵二叉树的头节点head,返回这颗二叉树是不是平衡二叉树

思路:递归方法



    public static boolean isBalanced1(Node head) {
        if(head == null)
            return true;
        Info ans = process(head);
        return ans.isblance;
    }

    // 以当前节点为根节点的二叉树,返回该二叉树是否为平衡二叉树
    public static Info process(Node head){
        if(head == null)
            return new Info(true,0);
        Info l = process(head.left);
        Info r = process(head.right);
        boolean is = false;
        // 不管左右子树是否为平衡二叉树 直接计算,调用方最终需要的不是高度而是 是否平衡
        int height = Math.max(l.height,r.height)+1;
        // process方法返回对象一定不为null
        if(l.isblance && r.isblance && Math.abs(l.height-r.height)<=1){
            is = true;
        }
        return new Info(is,height);

    }
    static class  Info {
        private boolean isblance;
        private Integer height ;

        public Info(boolean isblance, Integer height) {
            this.isblance = isblance;
            this.height = height;
        }
    }

题目:给定一棵二叉树的头节点head,返回这颗二叉树是不是满二叉树

思路:层次遍历上一层和当前层数量二倍关系,特殊情况最后一层遍历时候需要特殊处理

public static boolean isFull1(Node head) {
        if(head == null)
            return true;
        // 层次遍历 判断上一层和当前层数量是否二倍关系
        LinkedList<Node> queue = new LinkedList<>();
        queue.add(head);
        while (!queue.isEmpty()){
            // 用于判断是否为最后一行
            boolean allNull = true;
            int pre = queue.size();
            for (int i = 0; i < pre; i++) {
                Node cur = queue.poll();
                if(cur.left != null){
                    queue.add(cur.left);
                    allNull = false;
                }
                if(cur.right != null){
                    queue.add(cur.right);
                    allNull = false;
                }
            }
            int nextlen = queue.size();
            // 不是最后一行,name上一层和当前层节点数量一定是二倍关系
            if(!allNull && nextlen != 2*pre){
                return false;
            }
        }
        return true;
    }

思路2:递归方法,返回左右子树是否为满二叉树


    static class Info{
        private boolean isFull;
        private int height ;

        public Info(boolean isFull, int height) {
            this.isFull = isFull;
            this.height = height;
        }
    }

    public static boolean isFull2(Node head) {
        if(head == null)
            return true;

        Info process = process(head);
        return process.isFull;
    }
    public static Info process(Node head){
        if(head == null){
            return new Info(true,0);
        }
        Info l = process(head.left);
        Info r = process(head.right);
        boolean isFull = false;
        int height = Math.max(l.height,r.height)+1;
        if(l.isFull && r.isFull && l.height == r.height){
            isFull = true;
        }
        return new Info(isFull,height);
    }

题目:给定一棵二叉树的头节点head,返回这颗二叉树中最大的二叉搜索子树的大小

思路:递归返回子树作为根节点二叉搜索树信息

public static class TreeNode {
		public int val;
		public TreeNode left;
		public TreeNode right;

		public TreeNode(int value) {
			val = value;
		}
	}

	// 提交如下的代码,可以直接通过
	public static int largestBSTSubtree(TreeNode head) {
		if (head == null) {
			return 0;
		}
		return process(head).maxBSTSubtreeSize;
	}

	public static class Info {
		public int maxBSTSubtreeSize;
		public int allSize;
		public int max;
		public int min;

		public Info(int m, int a, int ma, int mi) {
			maxBSTSubtreeSize = m;
			allSize = a;
			max = ma;
			min = mi;
		}
	}

	public static Info process(TreeNode x) {
		if (x == null) {
			return null;
		}
		Info leftInfo = process(x.left);
		Info rightInfo = process(x.right);
		int max = x.val;
		int min = x.val;
		int allSize = 1;
		if (leftInfo != null) {
			max = Math.max(leftInfo.max, max);
			min = Math.min(leftInfo.min, min);
			allSize += leftInfo.allSize;
		}
		if (rightInfo != null) {
			max = Math.max(rightInfo.max, max);
			min = Math.min(rightInfo.min, min);
			allSize += rightInfo.allSize;
		}
		int p1 = -1;
		if (leftInfo != null) {
			p1 = leftInfo.maxBSTSubtreeSize;
		}
		int p2 = -1;
		if (rightInfo != null) {
			p2 = rightInfo.maxBSTSubtreeSize;
		}
		int p3 = -1;
		boolean leftBST = leftInfo == null ? true : (leftInfo.maxBSTSubtreeSize == leftInfo.allSize);
		boolean rightBST = rightInfo == null ? true : (rightInfo.maxBSTSubtreeSize == rightInfo.allSize);
		if (leftBST && rightBST) {
			boolean leftMaxLessX = leftInfo == null ? true : (leftInfo.max < x.val);
			boolean rightMinMoreX = rightInfo == null ? true : (x.val < rightInfo.min);
			if (leftMaxLessX && rightMinMoreX) {
				int leftSize = leftInfo == null ? 0 : leftInfo.allSize;
				int rightSize = rightInfo == null ? 0 : rightInfo.allSize;
				p3 = leftSize + rightSize + 1;
			}
		}
		return new Info(Math.max(p1, Math.max(p2, p3)), allSize, max, min);
	}

题目:给定一棵二叉树的头节点head,任何两个节点之间都存在距离,
返回整棵二叉树的最大距离

思路:递归方法,最大宽度,要么经过当前节点,要么是左右子树任意一个最长路径

public static Info process(Node head){
        if(head == null){
            return null;
        }
        Info left = process(head.left);
        Info right = process(head.right);
        // 最大宽度经过当前head节点
        int has = 1;
        int maxwide = 0;
        int depth = 0;
        if(left != null){
            has += left.maxdepth;
            maxwide = Math.max(left.maxwide,maxwide);
            depth = Math.max(depth,left.maxdepth);
        }
        if(right != null){
            has += right.maxdepth;
            maxwide = Math.max(right.maxwide,maxwide);
            depth = Math.max(depth,right.maxdepth);
        }
        // 最大宽度要么经过当前节点,要么在左右任意子树
        maxwide = Math.max(has,maxwide);
        return new Info(depth+1,maxwide);
    }
    static class Info{
        // 最大深度
        private int maxdepth;
        // 最大宽度
        private int maxwide;

        public Info(int maxdepth, int maxwide) {
            this.maxdepth = maxdepth;
            this.maxwide = maxwide;
        }
    }

问题:给定字符串数组,返回所有组合中字典排序最小的组合对应的字符串

思路:1 暴力方法,获取所有排列组合,然后取字典排序最小的

// process 拿到所有的排列租户,然后找到最小的一个并返回
    public static String lowestString1(String[] strs) {
        // PC
        if (strs == null || strs.length <= 0) return "";

        TreeSet<String> process = process(strs);
        return process.size() == 0 ? "" : process.first();
    }

    // 返回当前数组 arrs 的所有组合
    public static TreeSet<String> process(String[] arrs) {
        TreeSet<String> ans = new TreeSet<>();
        if (arrs == null || arrs.length <= 0) {
            ans.add("");
            return ans;
        }

        for (int i = 0; i < arrs.length; i++) {
            String[] strings = removeIndex(arrs, i);
            TreeSet<String> process = process(strings);
            for (String string : process) {
                ans.add(arrs[i] + string);
            }
        }
        return ans;
    }

    public static String[] removeIndex(String[] arrs, int index) {
        int N = arrs.length;
        String[] ans = new String[N-1];
        int j = 0;
        for (int i = 0; i < arrs.length; i++) {
            if (i == index) continue;
            ans[j++] = arrs[i];
        }
        return ans;
    }

方法2 :贪心算法,维护优先队列,将目标字符串元素加入队列,最终的队列即使字典排序最小的组合。优先队列指定比较器

public static String lowestString2(String[] strs) {
        if (strs == null || strs.length == 0) return "";
        // 1 优先队列 将元素依次放入
        Arrays.sort(strs,new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return (o1 + o2).compareTo(o2 + o1);
            }
        });

        // 2 最终的队列就是结果
        StringBuilder sb = new StringBuilder();
        for (String str : strs) {
            sb.append(str);
        }
        return sb.toString();
    }

需要注意的是:往队列塞入元素时候,如果在比较i位置元素时候就确定大小顺序,i之前的所有元素是不会进行比较的,所以这里存在一个问题,咋判断当前插入元素和i之前的元素组合就不是最小的。论证如下文章来源地址https://www.toymoban.com/news/detail-831472.html


递推法
队列初始有两个字符串 a  b  并且 ab 字典序小于 ba ,所以a排在b前面
当前字符串c需要进入队列,和b进行比较,字典序大于b所以排在b后面,
比较a 和 c的字典序
字符串ac可以转换为 N(a)*M(c)+N(c) K进制的数字, 其中M(c): Math.sqrt(K,c.length) N(a) 为字符串a对应的K进制数字
字符串ca可以转换为 N(c)*M(a)+N(a)
现在需要求  N(c)*M(a)+N(a) <  N(a)*M(c)+N(c) 
已知:
ab<ba
N(a)*M(b)+N(b) < N(b)*M(a)+N(a)  公式1
bc<cb
N(b)*M(c)+N(c) < N(c)*M(b)+N(b)  公式2 

公式1 两边同时减去 N(b) 后同时乘 N(c) 因为数字不为负数所以不改变比较符号
N(a)*M(b)*N(c) < N(c)*N(b)*M(a) + N(a)*N(c) - N(b)*N(c)    公式3
公式2 两边同时减去 N(b) 后同时乘 N(a) 因为数字不为负数所以不改变比较符号
N(b)*M(c)*N(a) +N(c)*N(a)-N(b)*N(a) < N(c)*M(b)*N(a)    	公式4
公式3 左边等于公式4右边 整理得
N(b)*M(c)*N(a) +N(c)*N(a)-N(b)*N(a) < N(c)*N(b)*M(a) + N(a)*N(c) - N(b)*N(c) 
N(b)*M(c)*N(a)-N(b)*N(a) < N(c)*N(b)*M(a)- N(b)*N(c) 
M(c)*N(a) -N(a) < N(c)*M(a) -N(c) 
M(c)*N(a) +N(c) < N(c)*M(a) +N(a) 
最终得
ac<ca
所以得到结论,ab<ba 并且 bc<cb 那么 ac 一定小于 ca

如果队列前面有n个已排序字符串 现在往里面塞 字符串 s,并且 arr[n-1]+s < s+arr[n-1] 
那么可以得到 [0,n-1) 和字符串 s 存在这样的关系 Str(0,n-2)+s < s+ Str(0,n-2) 
其中Str(0,n-2) 为[0,n-2] 范围任意长度字符串组合

最终得到结论,按照代码Comparator方式插入队列后,最终的队列就是字典序最小的组合

到了这里,关于算法-二叉树相关的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 树,二叉树及其相关知识

    1.1树的概念 树是一种非线性的数据结构,它是由n(n=0)个有限结点组成一个具有层次关系的集合。 把它叫做树是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。 有一个特殊的结点,称为根结点,根节点没有前驱结点 除根节点外,其余结点被分成M(M0)个

    2024年01月25日
    浏览(27)
  • 二叉树的遍历及相关衍生

    如标题所示,在这里我们要研究的是二叉树的遍历。 为什么不讲二叉树的增删查改? 在实际使用过程中,二叉树的增删查改没有多大作用,二叉树是作为一种数据结构, 不是用来存储数据,更多的是用来进行搜索 赫赫有名的红黑树和B树,都是其的限制优化的产物之一。 但

    2024年02月01日
    浏览(82)
  • 数据结构:二叉树及相关操作

    在实现二叉树前,我们要先对树产生一些基本的认识,才可以去实现它。树的用途非常广泛,向文件系统的目录树结构等。 树是一种 非线性的数据结构 ,它是由n(n=0)个有限结点组成一个具有层次关系的集合。 有一个特殊的结点,称为根结点,根节点没有前驱结点。 除根

    2024年02月11日
    浏览(46)
  • 二叉树相关的简单递归oj

    这篇博客主要是博主感觉对二叉树oj题目不太熟悉,随便整理的一下题目和解答,方便复习,所以讲题部分主要以我自己以及为我以后便于复习的简便语言来描述,看官可以当作的题目随便刷一下,如果看不懂可以自己画一下递归展开图。 oj链接:https://leetcode.cn/problems/binar

    2024年02月02日
    浏览(27)
  • 二叉树相关操作---纯代码实现详解

    目录 前言 (很重要) 二叉树的概念 二叉树的相关术语 相关操作菜单   二叉树的构造  创建二叉树 先序遍历二叉树    中序遍历二叉树  后序遍历二叉树  层次遍历二叉树  二叉树的深度  二叉树的叶子结点数  二叉树的结点数 整体代码 结果展示 结束语         大家好,

    2023年04月09日
    浏览(31)
  • 【数据结构】二叉树 链式结构的相关问题

     本篇文章来详细介绍一下二叉树链式结构经常使用的相关函数,以及相关的的OJ题。 目录 1.前置说明 2.二叉树的遍历 2.1 前序、中序以及后序遍历 2.2 层次遍历 3.节点个数相关函数实现 3.1 二叉树节点个数 3.2 二叉树叶子节点个数 3.3 二叉树第k层节点个数 3.4 在二叉树中查找值

    2024年02月14日
    浏览(59)
  • 树和二叉树的相关概念及结构

    目录 1.树的概念及结构 1.1 树的概念 1.2 树的相关概念 1.3 树的表示 1.3.1 孩子兄弟表示法 1.3.2 双亲表示法 1.4 树的实际应用 2.二叉树的概念及结构 2.1 二叉树的概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储 2.4.1 顺序存储 2.4.2 链式存储 树是一种 非线性 的数据结构,

    2024年02月09日
    浏览(41)
  • DS:树及二叉树的相关概念

                                                     创作不易,兄弟们来波三连吧!!            树是一种非线性的数据结构,它是由n(n=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

    2024年03月13日
    浏览(68)
  • 【数据结构】——树和二叉树的相关习题

    1、设高度为h的二叉树上只有度为0和度为2的结点,则该二叉树中所包含的结点数至少为(),最多为()。 A、h ;2 h -1 B、2h-1 ; 2 h -1 C、2h+1; 2 h-1 -1 D、h+1;2 h -1 解析: (B) 最少的情况下,除了根结点该层为1个结点以外,其余h-1层都有2个结点,得2(h-1),即2(h-1)+1=2h-1。

    2024年02月03日
    浏览(45)
  • 【数据结构】——树和二叉树相关概念(全网超级详解)

       创作不易,家人们来一波三连吧?! 世界上最大的树--雪曼将军树,这棵参天大树不是最长也不是最宽,是不是很奇怪,大只是他的体积是最大的,看图片肯定是感触不深,大家可以自己去看看  扯远了,这次我们介绍的是一种新的数据结构--树 之前的栈和队列,都是一

    2024年04月08日
    浏览(69)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包