Java数据结构第十五期:走进二叉树的奇妙世界(四)

news2025/3/3 11:47:17

专栏:Java数据结构秘籍

个人主页:手握风云

目录

一、二叉树OJ练习题(续)

1.1. 二叉树的层序遍历

1.2. 二叉树的最近公共祖先

1.3. 从前序与中序遍历序列构造二叉树

1.4. 从中序与后序遍历序列构造二叉树

1.5. 根据二叉树创建字符串

一、二叉树OJ练习题(续)

1.1. 二叉树的层序遍历

     层序遍历,就是从左到右依次访问每个节点。这里我们要借助队列来非递归方式的实现。我们先将根结点root放入队列,再用cur引用来接收弹出的根结点最后再打印。当左右子树不为空时,再一次将左子树和右子树放入队列中。然后先弹出左子树,如果左子树的左右结点不为空,再次放入。当队列为空时,遍历过程结束。所以下面这棵二叉树的打印结果应为“4271369”。

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

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

    public TreeNode() {}

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

    public TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right import java.util.LinkedList;
import java.util.Queue;

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

    public TreeNode() {}

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

    public TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

public class Solution {
    public void levelOrder(TreeNode root){
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);

        while(! queue.isEmpty()){
            TreeNode cur = queue.poll();
            System.out.print(cur.val+" ");

            if(cur.left != null){
                queue.offer(cur.left);
            }

            if(cur.right != null){
                queue.offer(cur.right);
            }
        }
    }
}= right;
    }
}

public class Solution {
    public void levelOrder(TreeNode root){
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);

        while(! queue.isEmpty()){
            TreeNode cur = queue.poll();
            System.out.print(cur.val+" ");

            if(cur.left != null){
                queue.offer(cur.left);
            }

            if(cur.right != null){
                queue.offer(cur.right);
            }
        }
    }
}
public class Test {
    public static void main(String[] args) {
        TreeNode root = new TreeNode(4,new TreeNode(2),new TreeNode(7));

        root.left.left = new TreeNode(1);
        root.left.right = new TreeNode(3);

        root.right.left = new TreeNode(6);
        root.right.right = new TreeNode(9);

        Solution solution = new Solution();
        solution.levelOrder(root);
    }
}

       但题目当中给出的类型是嵌套List<List<Integer>>,同时根据输出的格式来,创建一个二维数组,第一层放入第一列中。我们依然可以借助上面的队列来实现。与上面的方法类似,我们还需要再定义一个整型size变量来接受队列的长度,根据队列的长度来选择弹出与进入的操作。

public List<List<Integer>> levelOrder1(TreeNode root){
        List<List<Integer>> ret = new ArrayList<>();
        if(root == null) return ret;

        Queue<TreeNode> queue1 = new LinkedList<TreeNode>();
        queue1.offer(root);

        while(! queue1.isEmpty()){
            List<Integer> curList = new ArrayList<>();
            int size = queue1.size();

            while(size != 0){
                TreeNode cur = queue1.poll();
                curList.add(cur.val);
                if(cur.left != null){
                    queue1.offer(cur.left);
                }

                if(cur.right != null){
                    queue1.offer(cur.right);
                }
                size--;
            }
            ret.add(curList);
        }
        return ret;
    }
import java.util.List;

public class Test {
    public static void main(String[] args) {
        Solution solution = new Solution();
        TreeNode root = new TreeNode(4,new TreeNode(2),new TreeNode(7));

        root.left.left = new TreeNode(1);
        root.left.right = new TreeNode(3);

        root.right.left = new TreeNode(6);
        root.right.right = new TreeNode(9);


        solution.levelOrder(root);

        List<List<Integer>> result = solution.levelOrder1(root);
        System.out.println(result);
    }
}

1.2. 二叉树的最近公共祖先

        如果是上图中第三种情况,那么我们就直接返回root。如果是第一种情况,当root向下遍历时,遇到p、q结点时,直接返回到root(如下图所示)。

        如果是第二种情况,当root遍历到p节点时,5结点返回p的地址,同时我们也可以找到q结点并返回。但还是有一种极端情况,q是孩子节点p的一个子结点。按照上面的思路,直接就返回这个结点。所以这种极端情况可以总结为,只要root遍历到p或者q中一个,直接返回对应的结点。因为p、q都在同一棵子树上,当root去遍历另一棵子树时,会返回null,所以最终结果是p,与p或q在根节点上是类似的。

        完整代码实现:

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

    public TreeNode() {}

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

    public TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

public class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
        if(root == null){
            return root;
        }

        if(root == p || root == q){
            return root;
        }

        TreeNode leftT = lowestCommonAncestor(root.left,p,q);
        TreeNode rightT = lowestCommonAncestor(root.right,p,q);

        if(leftT != null && rightT != null){//p、q分别在左右子树上
            return root;
        }else if(leftT != null){
            return leftT;
        } else if (rightT != null) {
            return rightT;
        }
        return null;
    }
}
public class Test {
    public static void main(String[] args) {
        TreeNode root = new TreeNode(3,new TreeNode(5),new TreeNode(1));
        root.left.left = new TreeNode(6);
        root.left.right = new TreeNode(2,new TreeNode(7),new TreeNode(4));
        root.right.left = new TreeNode(0);
        root.right.right = new TreeNode(8);

        TreeNode p = root.left;
        TreeNode q = root.right;

        Solution solution = new Solution();
        TreeNode cur = solution.lowestCommonAncestor(root,p,q);
        System.out.println(cur.val);
    }
}

        这道题还有另一种做法:如果我们把二叉树里的每一个结点新增加一个前驱域,用来存储父节点的地址,那么这道题的思路就变成了一链表交点的形式来求最近的公共祖先结点。可是定义的TreeNode类里面的成员变量里面没有这个变量。此时可以利用两个栈来存储从root到p、q结点路径上的结点。

        基本思路:只要root不为空,就把结点扔进栈当中。让长度较大的栈先弹出一定的元素,使得两个栈长度相等。两个栈再同时弹出元素,判断两个值是否相等,相等则是最近的公共祖先结点。

        而下面问题又来了,我们该如何求路径上的结点?只要root不等于p或者q,就将该节点放进栈中并继续递归;当root等于p或者q时,就停止。如果在遍历过程中某一个结点既不等于p、q,且左右都为空,那么这个元素就会被弹出。

        完整代码实现:

import java.util.Stack;

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

    public TreeNode() {}

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

    public TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

public class Solution {

    public boolean getPath(TreeNode root, TreeNode node, Stack<TreeNode> stack){
        if(root == null){
            return false;
        }
        stack.push(root);
        if(root == node){
            return true;
        }

        boolean flag = getPath(root.left,node,stack);
        if(flag){
            return true;
        }

        flag = getPath(root.right,node,stack);
        if(flag){
            return true;
        }

        stack.pop();
        return false;
    }
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
        if(root == null){
            return null;
        }

        Stack<TreeNode> stack1 = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();

        getPath(root,p,stack1);
        getPath(root,q,stack2);

        int len1 = stack1.size();
        int len2 = stack2.size();

        int len = len1 - len2;

        if(len < 0){
            len = Math.abs(len);
            while(len != 0){
                stack2.pop();
                len--;
            }
        }else{
            while(len != 0){
                stack1.pop();
                len--;
            }
        }

        //保证两个栈的长度一样
        while (!stack1.isEmpty() && !stack2.isEmpty()){
            if(stack1.peek() == stack2.peek()){
                return stack1.pop();
            }else{
                stack1.pop();
                stack2.pop();
            }
        }
        return null;
    }
}
public class Test {
    public static void main(String[] args) {
        TreeNode root = new TreeNode(3,new TreeNode(5),new TreeNode(1));
        root.left.left = new TreeNode(6);
        root.left.right = new TreeNode(2,new TreeNode(7),new TreeNode(4));
        root.right.left = new TreeNode(0);
        root.right.right = new TreeNode(8);

        TreeNode p = root.left;
        TreeNode q = root.right;

        Solution solution = new Solution();
        TreeNode cur = solution.lowestCommonAncestor(root,p,q);
        System.out.println(cur.val);
    }
}

1.3. 从前序与中序遍历序列构造二叉树

        基本思路:1.遍历前序遍历的数组,遇到元素之后,在中序遍历数组当中找到该数字;2.该数字的左边就是左树,右边就是右树。上述两步构成一个递归来构造子树。

        我们以中序遍历的数组的第一个元素ibegin,最后一个元素iend之间找到二叉树的根,因为是前序遍历,先有的左树再有的右树,那么左边的区间就会是(9,x) = (ibegin,iend),iend = iroot-1;相反我们去递归右树,ibegin=iroot+1。也就是说,递归根结点创建左树和右树时,还需要知道ibegin和iend的范围。

        我们还需要额外创建一个方法来接受ibegin和iend的参数。创建root,利用buildTreeChild方法递归来创建根结点的左树和右树。可我们不知道中序遍历的数组中根结点的下标,还需要一个方法来查找根结点的下标。

public class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder){
        return buildTreeChild(preorder,0,inorder,0, inorder.length-1);
    }

    public TreeNode buildTreeChild(int[] preorder, int prevIndex,int[] inorder, int inbegin, int inend){
        TreeNode root = new TreeNode(preorder[prevIndex]);
        int rootIndex = findIndex(inorder,inbegin,inend,preorder[prevIndex]);
        prevIndex++;
        root.left = buildTreeChild(preorder,prevIndex,inorder,inbegin,rootIndex-1);
        root.right = buildTreeChild(preorder,prevIndex,inorder,rootIndex-1,inend);
        return root;
    }
    private int findIndex(int[] inorder,int inbegin,int inend,int key) {
        for(int i = inbegin; i <= inend; i++) {
            if(inorder[i] == key) {
                return i;
            }
        }
        return -1;
    }
}

        但此时的代码还是有一点逻辑上的问题,就是递归结束的条件是什么?一棵二叉树,总有一棵子树的左右子树都为空。但我们上面的代码没有null。所以要处理一下边界情况:

if(inbegin > inend){
    return null;
}

        还存在另一个问题,就是局部变量的定义。因为二叉树遍历完左树的时候,最后给根返回0,从0再去遍历右子树。所以我们把prevIndex定义为成员变量。

        完整代码实现: 

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

    public TreeNode() {}

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

    public TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

public class Solution {
    public int prevIndex;

    public TreeNode buildTree(int[] preorder, int[] inorder){
        return buildTreeChild(preorder,inorder,0, inorder.length-1);
    }

    public TreeNode buildTreeChild(int[] preorder, int[] inorder, int inbegin, int inend){
        if(inbegin > inend){
            return null;
        }
        TreeNode root = new TreeNode(preorder[prevIndex]);
        int rootIndex = findIndex(inorder,inbegin,inend,preorder[prevIndex]);
        prevIndex++;
        root.left = buildTreeChild(preorder,inorder,inbegin,rootIndex-1);
        root.right = buildTreeChild(preorder,inorder,rootIndex+1,inend);
        return root;
    }
    private int findIndex(int[] inorder,int inbegin,int inend,int key) {
        for(int i = inbegin; i <= inend; i++) {
            if(inorder[i] == key) {
                return i;
            }
        }
        return -1;
    }
}
public class Test {
    public static void PrintTreeNode(TreeNode root){
        if(root == null){
            return;
        }
        System.out.print(root.val+" ");
        PrintTreeNode(root.left);
        PrintTreeNode(root.right);
    }

    public static void main(String[] args) {
        Solution soluion = new Solution();

        int[] preOrder = new int[]{3,9,20,15,7};
        int[] inOrder = new int[]{9,3,15,20,7};

        TreeNode root = soluion.buildTree(preOrder,inOrder);
        PrintTreeNode(root);
    }
}

1.4. 从中序与后序遍历序列构造二叉树

        与上面一题的思路一样,但后序遍历的顺序是“左子树、右子树、根”,那根结点从后面开始找。并且在创建树的过程中,要先创建右树再创建左树。

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

    public TreeNode() {}

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

    public TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

public class Solution {
    public int postIndex = 0;

    public TreeNode buildTree(int[] inorder, int[] postorder){
        postIndex = postorder.length-1;
        return buildTreeChild(postorder,inorder,0, inorder.length-1);
    }

    public TreeNode buildTreeChild(int[] preorder, int[] inorder, int inbegin, int inend){
        if(inbegin > inend){
            return null;
        }
        TreeNode root = new TreeNode(preorder[postIndex]);
        int rootIndex = findIndex(inorder,inbegin,inend,preorder[postIndex]);
        postIndex--;
        root.right = buildTreeChild(preorder,inorder,rootIndex+1,inend);
        root.left = buildTreeChild(preorder,inorder,inbegin,rootIndex-1);
        return root;
    }
    private int findIndex(int[] inorder,int inbegin,int inend,int key) {
        for(int i = inbegin; i <= inend; i++) {
            if(inorder[i] == key) {
                return i;
            }
        }
        return -1;
    }
}
public class Test {
    public static void PrintTreeNode(TreeNode root){
        if(root == null){
            return;
        }
        PrintTreeNode(root.left);
        PrintTreeNode(root.right);
        System.out.print(root.val+" ");
    }

    public static void main(String[] args) {
        Solution solution = new Solution();

        int[] Inorder = new int[]{9,3,15,20,7};
        int[] Postorder = new int[]{9,15,7,20,3};

        TreeNode root = solution.buildTree(Inorder,Postorder);
        PrintTreeNode(root);
    }
}

 

1.5. 根据二叉树创建字符串

        通过上图分析:当1的左子树不为空,就用一个(,2的左子树也不为空,也使用一个(,4再往下递归返回null,直接)闭合;2的右子树为null,返回);1的右子树不为空,返回(,3递归返回null,直接)闭合。

        所以我们可以总结下来规律:当子树不为空时,直接加左括号;当root的左树为空,且右树也为空,直接加右括号闭合;当root的左树不为空,右树为空,也加右括号闭合。

    public void tree2strChild(TreeNode root,StringBuilder stringBuilder){
        if(root == null){
            return;
        }
        stringBuilder.append(root.val);

        //判断根的左子树
        if(root.left != null){
            stringBuilder.append("(");
            tree2strChild(root.left,stringBuilder);//递归左树
            stringBuilder.append(")");//左树走完,右括号闭合
        }else {
            if(root.right == null){
                return;//因为4结点走完,返回2结点,这里本身就会加一个")"
            }else {

            }
        }

        //判断根的右子树
        if(root.right != null){
            stringBuilder.append("(");
            tree2strChild(root.right,stringBuilder);
            stringBuilder.append(")");
        }else {

        }
    }

        但也存在另一种情况:如果子树的左边为空,右边不为空,就直接加一对小括号,再去递归右树,把4再加进去。再继续往下走,如果root.right为空,正好符合上面2结点的情况:2的左边走完,右边为空,直接return加右括号。所以只要左树为空,右树不为空,就不做任何处理。

        完整代码实现:

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

    public TreeNode() {}

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

    public TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

public class Solution {
    public String tree2str(TreeNode root){
        StringBuilder stringBuilder = new StringBuilder();
        tree2strChild(root,stringBuilder);
        return stringBuilder.toString();
    }

    public void tree2strChild(TreeNode root,StringBuilder stringBuilder){
        if(root == null){
            return;
        }
        stringBuilder.append(root.val);

        //判断根的左子树
        if(root.left != null){
            stringBuilder.append("(");
            tree2strChild(root.left,stringBuilder);//递归左树
            stringBuilder.append(")");//左树走完,右括号闭合
        }else {
            if(root.right == null){
                return;//因为4结点走完,返回2结点,这里本身就会加一个")"
            }else {
                stringBuilder.append("()");
            }
        }

        //判断根的右子树
        if(root.right != null){
            stringBuilder.append("(");
            tree2strChild(root.right,stringBuilder);
            stringBuilder.append(")");
        }else {
            return;
        }
    }
}
public class Test {
    public static void main(String[] args) {
        Solution solution = new Solution();

        TreeNode root1 = new TreeNode(1,new TreeNode(2),new TreeNode(3));
        root1.left.left = new TreeNode(4);

        TreeNode root2 = new TreeNode(1,new TreeNode(2),new TreeNode(3));
        root2.left.right = new TreeNode(4);

        System.out.println(solution.tree2str(root1));
        System.out.println(solution.tree2str(root2));
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2308248.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Typora的Github主题美化

[!note] Typora的Github主题进行一些自己喜欢的修改&#xff0c;主要包括&#xff1a;字体、代码块、表格样式 美化前&#xff1a; 美化后&#xff1a; 一、字体更换 之前便看上了「中文网字计划」的「朱雀仿宋」字体&#xff0c;于是一直想更换字体&#xff0c;奈何自己拖延症…

Cursor配置MCP Server

一、什么是MCP MCP&#xff08;Model Context Protocol&#xff09;是由 Anthropic&#xff08; Claude 的那个公司&#xff09; 推出的开放标准协议&#xff0c;它为开发者提供了一个强大的工具&#xff0c;能够在数据源和 AI 驱动工具之间建立安全的双向连接。 举个好理解…

定时器之输入捕获

输入捕获的作用 工作机制​ 输入捕获通过检测外部信号边沿&#xff08;上升沿/下降沿&#xff09;触发计数器&#xff08;CNT&#xff09;值锁存到捕获寄存器&#xff08;CCRx&#xff09;&#xff0c;结合两次捕获值的差值计算信号时间参数。 ​脉冲宽度测量&#x…

Uniapp开发微信小程序插件的一些心得

一、uniapp 开发微信小程序框架搭建 1. 通过 vue-cli 创建 uni-ap // nodejs使用18以上的版本 nvm use 18.14.1 // 安装vue-cli npm install -g vue/cli4 // 选择默认模版 vue create -p dcloudio/uni-preset-vue plugindemo // 运行 uniapp2wxpack-cli npx uniapp2wxpack --…

Pikachu

一、网站搭建 同样的&#xff0c;先下载安装好phpstudy 然后启动Apache和Mysql 然后下载pikachu&#xff0c;解压到phpstudy文件夹下的www文件 然后用vscode打开pikachu中www文件夹下inc中的config.inc.php 将账户和密码改为和phpstudy中的一致&#xff08;默认都是root&…

CentOS7 使用 YUM 安装时报错:Cannot find a valid baseurl for repo: base/7/x86_64的解决方法

CentOS7 使用 YUM 安装时报错&#xff1a;Cannot find a valid baseurl for repo: base/7/x86_64的解决方法 报错代码解决方法 报错代码 输入命令yum update -y时报错Cannot find a valid baseurl for repo: base/7/x86_64 解决方法 有 wget 工具 更换YUM源 mv /etc/yum.…

Linux----网络通信

一、IP地址详解 &#xff08;一&#xff09;核心概念 概念说明IP地址网络设备的唯一逻辑标识符&#xff0c;相当于网络世界的"门牌号"主机任何接入网络的终端设备&#xff08;计算机/手机/服务器等&#xff09;核心作用① 设备标识 ② 路由寻址 ③ 数据传输 &…

【MySQL篇】数据类型

目录 前言&#xff1a; 1&#xff0c;数据类型的分类 ​编辑 2 &#xff0c;数值类型 2.1 tinyint类型 2.2 bit类型 2.3 小数类型 2.3.1 float类型 2.3.2 decimal类型 3&#xff0c;字符串类型 3.1 char 3.2 varchar 3.3 char与varchar的比较 3.4日期和时间类型 3.5 …

【音视频】图像基础概念

一、图像基础概念 1.1 像素 像素是一个图片的基本单位&#xff0c;pix使英语单词pixtureelement的结合“pixel”的简称&#xff0c;所以像素有图像元素之意。 例如2500*2000的照片就是指横向有2500个像素点&#xff0c;竖向有2000个像素点&#xff0c;总共500万个像素&#x…

时钟树的理解

对应电脑的主板&#xff0c;CPU&#xff0c;硬盘&#xff0c;内存条&#xff0c;外设进行学习 AHB总线 -72MHZ max APB1总线 -36MHZ max APB2-72MHZ max 时序逻辑电路需要时钟线控制 &#xff0c;含有记忆性的原件的存在。&#xff08;只有时钟信号才能工作&…

CentOS vs Ubuntu - 常用命令深度对比及最佳实践指南20250302

CentOS vs Ubuntu - 常用命令深度对比及最佳实践指南 引言 在 Linux 服务器操作系统领域&#xff0c;CentOS 和 Ubuntu 是广泛采用的发行版。它们在命令集、默认工具链及生态系统方面各有特点。本文深入剖析 CentOS 与 Ubuntu 在常用命令层面的异同&#xff0c;并结合实践案例…

问题修复-后端返给前端的时间展示错误

问题现象&#xff1a; 后端给前端返回的时间展示有问题。 需要按照yyyy-MM-dd HH:mm:ss 的形式展示 两种办法&#xff1a; 第一种 在实体类的属性上添加JsonFormat注解 第二种&#xff08;建议使用&#xff09; 扩展mvc框架中的消息转换器 代码&#xff1a; 因为配置类继…

为AI聊天工具添加一个知识系统 之127 详细设计之68 编程 核心技术:Cognitive Protocol Language 之1

本文要点 要点 今天讨论的题目&#xff1a;本项目&#xff08;为使用AI聊天工具的两天者加挂一个知识系统&#xff09; 详细程序设计 之“编程的核心技术” 。 source的三个子类&#xff08;Instrument, Agent, Effector&#xff09; 分别表示--实际上actually &#xff0c;…

多个pdf合并成一个pdf的方法

将多个PDF文件合并优点&#xff1a; 能更容易地对其进行归档和备份.打印时可以选择双面打印&#xff0c;减少纸张的浪费。比如把住宿发票以及滴滴发票、行程单等生成一个pdf&#xff0c;双面打印或者无纸化办公情况下直接发送给财务进行存档。 方法: 利用PDF24 Tools网站 …

周边游平台设计与实现(代码+数据库+LW)

摘 要 在如今社会上&#xff0c;关于信息上面的处理&#xff0c;没有任何一个企业或者个人会忽视&#xff0c;如何让信息急速传递&#xff0c;并且归档储存查询&#xff0c;采用之前的纸张记录模式已经不符合当前使用要求了。所以&#xff0c;对旅游信息管理的提升&#xff0c…

python量化交易——金融数据管理最佳实践——qteasy创建本地数据源

文章目录 qteasy金融历史数据管理总体介绍本地数据源——DataSource对象默认数据源查看数据表查看数据源的整体信息最重要的数据表其他的数据表 从数据表中获取数据向数据表中添加数据删除数据表 —— 请尽量小心&#xff0c;删除后无法恢复&#xff01;&#xff01;总结 qteas…

⭐算法OJ⭐矩阵的相关操作【动态规划 + 组合数学】(C++ 实现)Unique Paths 系列

文章目录 62. Unique Paths动态规划思路实现代码复杂度分析 组合数学思路实现代码复杂度分析 63. Unique Paths II动态规划定义状态状态转移方程初始化复杂度分析 优化空间复杂度状态转移方程 62. Unique Paths There is a robot on an m x n grid. The robot is initially lo…

Baklib云内容中台的核心架构是什么?

云内容中台分层架构解析 现代企业内容管理系统的核心在于构建动态聚合与智能分发的云端中枢。以Baklib为代表的云内容中台采用三层架构设计&#xff0c;其基础层为数据汇聚工具集&#xff0c;通过标准化接口实现多源异构数据的实时采集与清洗&#xff0c;支持从CRM、ERP等业务…

一个基于vue3的图片瀑布流组件

演示 介绍 基于vue3的瀑布流组件 演示地址: https://wanning-zhou.github.io/vue3-waterfall/ 安装 npm npm install wq-waterfall-vue3yarn yarn add wq-waterfall-vue3pnpm pnpm add wq-waterfall-vue3使用 <template><Waterfall :images"imageList&qu…

【pytest框架源码分析一】pluggy源码分析之hook常用方法

简单看一下pytest的源码&#xff0c;其实很多地方是依赖pluggy来实现的。这里我们先看一下pluggy的源码。 pluggy的目录结构如下&#xff1a; 这里主要介绍下_callers.py, _hooks.py, _manager.py&#xff0c;其中_callers.py主要是提供具体调用的功能&#xff0c;_hooks.py提…