Java 【数据结构OJ题十道】—— 二叉树篇1

news2024/11/29 2:48:31

文章目录

  • 一、 检查两棵二叉树是否相同
  • 二、 另一棵二叉树的子树
  • 三、 二叉树的构建及遍历
  • 四、序列化二叉树和反序列化二叉树(难)
  • 五、二叉树创建字符串
  • 六、 二叉树前序非递归遍历实现
  • 七、 二叉树中序非递归遍历实现
  • 八、 二叉树后序非递归遍历实现
  • 九、二叉搜索树中找到两个结点的最近公共祖先
  • 十、二叉树中找到两个结点的最近公共祖先
  • 总结


提示:本人是正在努力进步的小菜鸟,不喜勿喷~,如有大佬发现某题有更妙的解法和思路欢迎提出讨论~

一、 检查两棵二叉树是否相同

OJ链接

📌📌📌题目描述:
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的
返回值: boolean


📌📌📌解题思路:
两棵树同时递归, 每遍历到一个结点就判断
1️⃣当 p, q, 一个为空一个不为空时, 返回 false
2️⃣当 p, q, 的val值不同时, 返回 false
3️⃣当 p, q, 同时遍历到空结点时, 说明 p, q 的所有祖先点相同, 返回 true

⚠️⚠️⚠️注意:
不能 p, q, 同时不为空且值相同时就返回 true, 因为有可能这个结点暂时相同, 但子树的结点还不能相同, 一定是当 p, q, 同时遍历到空结点时, 才说明这一路的结点没有返回 false, 那么此时 p, q 的所有祖先点相同, 才能返回true

    public boolean isSameTree(TreeNode p, TreeNode q) {
    	// p, q, 有其中一个不为空
        if ( (p == null && q != null ) || (p != null && q == null) ) {
            return false;
        }
        // val不相同的情况
        if (p.val != q.val) {
            return false;
        }
        // p, q, 都为空的情况
        if (p == null && q == null) {
            return true;
        }
        // 左右子树都要判断
        return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    }

二、 另一棵二叉树的子树

OJ链接

📌📌📌题目描述:
给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false
二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树
返回值: boolean


📌📌📌解题思路:
上一题就是 判断两棵二叉树是否相同, 判断一棵树是否是另一颗的子树, 只需要遍历以 root 为根的树的每一个结点, 和以 subRoot 为根的树, 只要是相同的树则说明 root 这棵树中有 subRoot 这棵树, 所以上一题的代码可以直接拿来用

题目描述中说 tree 也可以看做它自身的一棵子树 , 说明: 如果给定的 root 和 subRoot 本身就是相同的树, 也符合题目要求, 所以首先要对给定的 root 和 subRoot 判断是否为同一棵树
然后利用子问题思想: 让 root 的左右子树递归判断是否存在一个结点和 subRoot 是相同的树

⚠️⚠️⚠️注意:
虽然题目给定两个树的结点范围是[1,2000], 说明两棵树都不为空, 但是不能省略代码中对 root 和 sunRoot 的判空, 因为:
1️⃣在上一题分析过, 当 p, q, 同时遍历到空结点时, 说明 p, q 的所有祖先点相同, 返回 true, 所以 root 和subRoot 都需要遍历到空结点
2️⃣还有一种情况是 root 这棵树的所有结点都遍历完了也不满足和 subRoot 是同一棵树, 所以要返回 false

    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
		// 当root遍历到null还没找到和subRoot相同的树
        if(root == null) {
            return false;
        }
        if(isSameTree(root,subRoot)) {
            return true;
        }
        // 遍历,左右子树有一边满足条件即可
        return isSubtree(root.left,subRoot) || isSubtree(root.right,subRoot);
    }
    private boolean isSameTree(TreeNode root, TreeNode subRoot) {
        if(root == null && subRoot == null) {
            return true;
        }
        if((root != null && subRoot == null) || (root == null && subRoot != null)) {
            return false;
        }
        if(root.val != subRoot.val) {
            return false;
        }
        return isSameTree(root.left,subRoot.left)  && isSameTree(root.right,subRoot.right);
    }

三、 二叉树的构建及遍历

OJ链接

📌📌📌题目描述:
编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储), 例如如下的先序遍历字符串: ABC##DE#G##F### 其中 “#” 表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。
返回值: void


📌📌📌解题思路:
题目分成两部分: 利用字符串构造二叉树+ 中序遍历
中序遍历很简单, 主要是如何利用字符串构造二叉树, 根据题目描述, 给定的字符串是前序遍历, 所以我们利用字符串构建二叉树时也应该使用前序遍历的顺序

需要一个变量 i 表示下标, 当 i 为 # 时表示 null, null 能 new 出结点吗? 当然不能, i++ 即可, 当 i 不为 # 时, new 出一个结点, 然后别忘了也要 i++

以根节点为例: 根节点不为空: new了一个结点, i++ , 然后让根结点往左递归, 链接下一个结点(每一个结点都是这样的方式), 直到 i 访问到 # , 栈帧空间一路返回, 链接每一个结点的右子树
最终返回这棵树的根节点, 以便进行中序遍历

⚠️⚠️⚠️注意:
题目设置了多组输入的情况, 所以要利用 Scanner in = new Scanner(System.in) 处理多组输入

public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String str = in.nextLine();
            TreeNode root = creatTree(str);
            inOrder(root);
        }
    }
    public static int i = 0;
    private static TreeNode creatTree(String str) {
        TreeNode root = null;
        if(str.charAt(i) != '#') {
            root = new TreeNode(str.charAt(i));
            i++;
            root.left = creatTree(str);
            root.right = creatTree(str);
        }else {
        	// 当 i 遍历到 # 时
            i++;
        }
        return root;
    }
    private static void inOrder(TreeNode root){
        if(root == null) {
            return;
        }
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }

四、序列化二叉树和反序列化二叉树(难)

OJ链接

📌📌📌题目描述:
请实现两个函数,分别用来序列化反序列化二叉树,不对序列化之后的字符串进行约束,但要求能够根据序列化之后的字符串重新构造出一棵与原二叉树相同的树


二叉树的序列化(Serialize)是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树等遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#)
// 简单来说: 序列化: 二叉树 => 字符串

二叉树的反序列化(Deserialize)是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树
// 简单来说: 反序列化: 字符串 => 二叉树
在这里插入图片描述
返回值: 序列化返回String 和 反序列化TreeNode


📌📌📌解题思路:
反序列化: 以前序遍历的方式实现对二叉树的反序列化和上一题思路基本一致

序列化:

返回值要求是String, 系统会检查你的字符串格式, 需要有 {} 括起来每一个结点的val值, 并且有逗号分隔

首先append一个'{' , 同样使用前序遍历的方式, 只需对每个结点判断:
如果结点不为空, 直接append该结点val值和逗号
如果结点为空, append 井号和逗号
无论哪种情况, 当最后一次append之后会多余一个逗号, 要利用deleteCharAt() 方法删除这个逗号, 最后再appen一个'}'

⚠️⚠️⚠️注意:
反序列化方法的核心是要找到字符串中的有效字符, 也就是数字字符, 但题目说明每一个结点的val值范围: [0,150], 所以有效数字字符可能不止一位,
如果 i 下标访问到有效(数字)字符, 需要找到下一个逗号之前的 所有数字字符, 得到的是一个字符串, 要把这个字符串转化成 int 类型, 作为val值new出结点

所以在反序列化中注意以下几个方法的使用
charAt(): 参数是 int 类型, 表示下标. 返回值是 char 类型
用于在字符串中访问任意下标(从 0 开始)的值, 小心越界 !!!
subsrting() : 参数是两个 int 类型, 表示开始和结束下标. 返回值是 String 类型
用于截取字符串, 注意范围是左开右闭
Integer.parseInt() : 参数是 String 类型的字符串, 返回值是 int 类型
用于把纯数字字符串转化成数字, 参数中不能有非数字字符,否则会报NumberFormatException异常

要经常考虑使用subsrting()方法的情况, 使用该方法需要确定开始下标和结束下标, 所以 把寻找结束位置下标封装成一个方法: findEndIndex()

    // 序列化: 二叉树 => 字符串
    public static String serialize(TreeNode root) {
        // 先new一个StringBuffer对象, 返回值是String, 最后要toString
        StringBuffer sb = new StringBuffer("{");
        // 判空
        if (root == null) {
            sb.append('}');
            return sb.toString();
        }
        // 利用前序遍历 遍历结点, append每一个结点val值+逗号
        preOrder(root, sb);
        sb.deleteCharAt(sb.length() - 1);
        // 删除最后一个逗号,再append一个}
        sb.append('}');
        return sb.toString();
    }
    private static void preOrder(TreeNode root, StringBuffer str) {
        if (root == null) {
            str.append('#').append(',');
            return;
        }
        str.append(root.val).append(',');
        preOrder(root.left, str);
        preOrder(root.right, str);
    }

    // 反序列化: 字符串 => 二叉树
    public static int i = 1; // 成员属性, 用来遍历字符串
    public static TreeNode Deserialize(String str) {
        TreeNode root = null;
        int len = str.length();
        // 如果字符串为空:"{}" => 1下标的字符是'}', 返回null
        if (str.charAt(i) == '}') {
            return root;
        }
        // 如果i下标的字符不是'#'
        if (str.charAt(i) != '#') {
            int startIndex = i; // 开始下标
            int endIndex = findEndIndex(str, len); // 结束下标
            // substring : [start, end) 截取str字符串中的数字字符串
            String ret = str.substring(startIndex, endIndex);
            // 转化成整形数字, new出结点
            root = new TreeNode(Integer.parseInt(ret));
            i++;
            root.left = Deserialize(str);
            root.right = Deserialize(str);
        } else {
            // 如果i下标的字符是'#', i往后走到下一个有效字符
            i += 2;
        }
        return root;
    }
    // 寻找end下标
    private static int findEndIndex(String str, int length) {
        while (i < length && str.charAt(i) != ',') {
            if (str.charAt(i) != '}') {
                i++;
            } else {
                break;
            }
        }
        return i;
    }
// 反序列化
    public static TreeNode Deserialize(String str) {
        TreeNode root = null;
        int i = 1;
        int len = str.length();
        if (str.charAt(i) == '}') {
            return root;
        } else {
            // new出字符串转化为数字的 结点
            String val = getStringVal(str,len);
            root = new TreeNode(Integer.parseInt(val));
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (i < len - 1) {
            TreeNode top = queue.poll();
            if(top != null) {
                String val = getStringVal(str, len);
                if (val.charAt(0) == '#') {
                    top.left = null;
                } else {
                    top.left = new TreeNode(Integer.parseInt(val));
                    queue.offer(top.left);
                }
                i++;

                if(val.charAt(0) == '#') {
                    top.right = null;
                } else {
                    top.right = new TreeNode(Integer.parseInt(val));
                    queue.offer(top.right);
                }
                i++;
            }
        }
        return root;
    }

五、二叉树创建字符串

OJ链接

📌📌📌题目描述:
给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。

空节点使用一对空括号对 “()” 表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。
在这里插入图片描述
在这里插入图片描述

返回值: String


📌📌📌解题思路:
根据前序遍历的顺序, 结合上图两个示例, 写出相应操作代码即可

⚠️⚠️⚠️注意:
树中节点的数目范围是 [1, 104], 保证树不为空, 所以可以省去对 root 的判空
也不比担心 root 会遍历到空结点, 因为每次递归前都会对 root 的 left 和 right 进行判断

    public String tree2str(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        convertedString(sb, root);
        return sb.toString();
    }
    private void convertedString(StringBuilder sb, TreeNode root){
        sb.append(root.val);
        if(root.left != null) {
            sb.append("(");
            convertedString(sb, root.left);
            sb.append(")");
        }else {
            // 左子树为空
            if(root.right != null){
                // 如果有右子树
            	sb.append("()");
            }else {
                // 如果没有右子树
                return;
            }
        }
        if(root.right != null) {
            sb.append("(");
            convertedString(sb, root.right);
            sb.append(")");
        }else {
            return;
        }
    }

六、 二叉树前序非递归遍历实现

OJ链接

📌📌📌题目描述:
给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
返回值: List<Integer>


📌📌📌解题思路:
递归的执行时的函数栈帧就是递出去再回退, 如果要模拟递归, 一般情况下都是使用栈, 前序遍历(根, 左, 右)二叉树的非递归实现就是, 没有递归就只能用利用while循环

在循环中遍历, 对于每个结点来说, 先把它访问了, root 不能存放其他结点的地址, 需要一个跑腿的变量 cur ,令 cur = root.left , 然后如果 cur 不为空就让 cur 入栈并访问, 再令 cur 往左走 当 cur 为空时退出循环 说明没有左子树了, 此时栈顶数据就是当前空结点的父节点(根) , 所以此时出栈栈顶元素, 就可以访问到根的右孩子结点

这样只是访问了第一个"右" , 那么还有很多个"右"如何范围呢, 当第一个"右"访问之后, 只说明当前的子树已经前序遍历完了, 栈还不为空, 还需要继续访问靠近根的那棵树的"右", 和递归类似, 还是上述的过程, 所以还需要加一个外循环, 栈为空时才说明最后一个"右"也访问完了


⚠️⚠️⚠️注意:
内循环的条件就是cur != null , 因为 cur 总是往左走, 要把"左"全部访问完才能访问"右", 当内循环退出时, 就令 cur = 出栈的结点的 right ,那么此时:
1️⃣cur == null, 继续让栈顶数据出栈, cur = 出栈的结点的 right , 访问其他(可能存在)的"右" , 直到栈为空为止
2️⃣cur != null, 继续入栈, 执行内循环, 所以外循环还有一个条件是 cur != null

上述两判断条件的逻辑关系是 || 而不是&&, 原因:
如果是一棵树没有左子树, 只有右子树的情况, 当 cur 遍历到根的左, 为空, 出栈根节点, 去访问根的右, 此时右不为空但栈为空, 只满足一个条件, 此时需要让cur执行内循环

综上, 外循环判断条件是cur != null || !stack.isEmpty()

	public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        if(root == null) {
            return ret;
        }
        // new一个顺序栈来模拟递归
        Deque<TreeNode> stack = new ArrayDeque<>();
        TreeNode cur = root;
        // 注意外循环的判断条件
        while (cur != null || !stack.isEmpty()) {
            while(cur != null) {
                stack.push(cur);
                ret.add(cur.val);
                cur = cur.left;
            }
            cur = stack.pop();
            cur = cur.right;
        }
        return ret;
    }

七、 二叉树中序非递归遍历实现

OJ链接

📌📌📌题目描述:
给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。
返回值: List<Integer>


📌📌📌解题思路:
和前序遍历大致相同, 只需要修改访问根节点的时机即可

   public List<Integer> inorderTraversal(TreeNode root) {
         List<Integer> ret = new ArrayList<>();
        if(root == null) {
            return ret;
        }
        Deque<TreeNode> stack = new ArrayDeque<>();
        TreeNode cur = root;
        while (cur != null || !stack.isEmpty()) {
            while(cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            ret.add(cur.val);
            cur = cur.right;
        }
        return ret;
    }

八、 二叉树后序非递归遍历实现

OJ链接

📌📌📌题目描述:
给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历
返回值: List<Integer>


📌📌📌解题思路:
前两题都是访问右结点在根节点之前, 访问过根节点之后就不需要了它了, 所以可以直接 pop, 但后序遍历需要先通过根节点访问到"右" , 返回去访问"根", 所以当 cur 遍历到空时, 先 peek 一下栈顶数据(如果 pop 就把根丢了, 回不去了) , 此时有两种情况:
1, 栈顶数据的右 == null , 那就不管了, 直接访问 peek 的数据, 访问完就 pop
2, 栈顶数据的右 != null , 让 cur = 栈顶数据的右, 执行内循环, 让右入栈

⚠️⚠️⚠️注意:
先看一下根据刚才分析实现的代码

		while (cur != null || !stack.isEmpty()) {
            while(cur!=null) {
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode top = stack.peek();
            if(top.right == null) {
                ret.add(top.val);
            }else {
                cur = top.right;
            }
        }

还有一个隐藏的问题 如图所示(前面步骤省略):
在这里插入图片描述
在这里插入图片描述

所以完整代码如下:

public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        if(root == null) {
            return ret;
        }
        Deque<TreeNode> stack = new ArrayDeque<>();
        TreeNode cur = root;
        TreeNode tmp = null;
        while (cur != null || !stack.isEmpty()) {
            while(cur!=null) {
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode top = stack.peek();
            if(top.right == null || top.right == tmp) {
                ret.add(top.val);
                tmp = stack.pop();
            }else {
                cur = top.right;
            }
        }
        return ret;
    }

九、二叉搜索树中找到两个结点的最近公共祖先

OJ链接

📌📌📌题目描述:
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
1️⃣对于该题的最近的公共祖先定义:对于有根树T的两个节点p、q,最近公共祖先LCA(T,p,q)表示一个节点x,满足x是p和q的祖先且x的深度尽可能大。在这里,一个节点也可以是它自己的祖先
2️⃣二叉搜索树是若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值 // 简单来说, 二叉搜索树的中序遍历序列满足有序
3️⃣所有节点的值都是唯一的。
4️⃣p、q 为不同节点且均存在于给定的二叉搜索树中。
数据范围:
3<=节点总数<=10000
0<=节点值<=10000
在这里插入图片描述
返回值: int


📌📌📌解题思路:
理解了二叉搜索树的特殊性质(第二条), 这题就很简单了, 递归遍历二叉树的每一个结点 , 分析共有以下几种情况:
1️⃣此时的结点的 val 是 p 或 q , 返回此结点
2️⃣是否 p , q 各自在此节点的两边, 返回此节点
3️⃣p,q 都在此结点的左边或右边, 在哪边就去哪边找, 不能返回此节点!!

⚠️⚠️⚠️注意:
上述第三种情况, 不能直接返回当前结点, 因为题目描述中说明了一个节点也可以是它自己的祖先, 以上图为例, 如果要找 4, 5 的最近公共祖先, 应该是 4, 而不是 1 或 7

    public int lowestCommonAncestor (TreeNode root, int p, int q) {
        return lowestCommonAncestorChild(root, p, q).val;
    }
    private TreeNode lowestCommonAncestorChild(TreeNode root, int p, int q) {
        if (root.val == p || root.val == q) {
            return root;
        } else if ((root.val > p && root.val < q) || (root.val < p && root.val > q)) {
            return root;
        } else if (root.val > p && root.val > q) {
            TreeNode ret = lowestCommonAncestorChild(root.left, p, q);
            return ret;
        } else {
            TreeNode ret = lowestCommonAncestorChild(root.right, q, p);
            return ret;
        }
    }

十、二叉树中找到两个结点的最近公共祖先

OJ链接

📌📌📌题目描述:
给定一棵二叉树(保证非空)以及这棵树上的两个节点对应的val值 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点。
1<=节点总数<=10^5
0<=节点值
注:本题保证二叉树中每个节点的val值均不相同。

在这里插入图片描述
所以节点值为 5 和节点值为 1 的节点的最近公共祖先节点的节点值为 3,所以对应的输出为 3。节点本身可以视为自己的祖先
返回值: int


📌📌📌解题思路:
虽然都是子问题思想, 但和上题不同, 因为上题可以利用二叉搜索树的性质, 它的结点分布是有一定规律的, 而普通二叉树没有节点大小的分布规律, 但是可以利用前序遍历去寻找

如果左树找到一个结点的 val 和 o1 或 o2 相等, 则直接返回这个结点, 不再继续往下寻找, 找不到返回 null
从栈帧空间返回去右树找是否有一个结点的 val 和 o1 或 o2 相等, 找到直接返回这个结点, 不再继续往下寻找, 找不到返回 null
当左右都找完了判断:
1️⃣有一边为空, 一边不为空, 说明不为空的那一边找到了最近公共祖先, 哪边不为空返回哪边
2️⃣两边都为空, 两边都没找到, 返回 null
3️⃣两边都不为空, 说明当前结点左右都找到了, 返回当前结点

⚠️⚠️⚠️注意:
1️⃣总体思路就是: 对每一棵树判断: 如果左找到了就去找右边, 看右边有没有 , 但是判定找到的条件一定是: 当前结点(不是当前结点的left或right)的 val 值 和 o1 或 o2 相等, 和上一题同理, 以本题的图为例, 2, 4 的公共祖先是2, 而不是 5 或 3
2️⃣记得每次递归调用要接收返回值

    public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
        return lowestCommonAncestorChild(root,o1,o2).val;
    }
    private TreeNode lowestCommonAncestorChild(TreeNode root, int o1, int o2) {
        if(root == null) {
            return null;
        }
        if(root.val == o1 || root.val == o2) {
            return root;
        }
        TreeNode leftRet = lowestCommonAncestorChild(root.left,o1,o2);
        
        TreeNode rightRet = lowestCommonAncestorChild(root.right,o1,o2);
        
        if(leftRet != null && rightRet == null) {
            return leftRet;
        }else if(leftRet == null && rightRet != null){
            return rightRet;
        }else if(leftRet == null || rightRet == null) {
            return null;
        }else {
            return root;
        }
    }


总结

以上是收录的十道关于二叉树的OJ题练习, 用作学习之余的整理分享, 仅供参考
如果本篇对你有帮助,请点赞收藏支持一下,小手一抖就是对作者莫大的鼓励啦😋😋😋~


上山总比下山辛苦
下篇文章见

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

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

相关文章

如何将电脑文件备份到百度网盘

如何将电脑文件备份到百度网盘&#xff1f;说到文件备份&#xff0c;很多小伙伴会将电脑文件备份到移动硬盘或者U盘里&#xff0c;移动硬盘和U盘是比较常见的存储介质&#xff0c;使用和携带起来也是非常方便&#xff0c;因此深受大家的喜欢。除此之外&#xff0c;大家可能还忽…

2023年,IT互联网还有发展前景吗?

不得不说&#xff0c;互联网在整个社会经济发展中扮演着不可或缺的角色&#xff1b;不仅自身的技术具有前沿性&#xff0c;也推动着其他行业进入数字化经济时代&#xff0c;让我们的工作生活变得更加便捷。 在“互联网”时代&#xff0c;每个服务行业都会利用大数据&#xff0…

将自带记事本替换为Notepad2【中文版,带替换文件】

Notepad2是我在寻找一个合适的代码浏览工具的时候发现的&#xff0c;当需要一个用来浏览代码的文本编辑器时候&#xff0c;需要体积小&#xff0c;速度快&#xff0c;语法高亮&#xff0c;解释度高&#xff0c;VsCode作为生产环境已经不适合作为浏览工具了。了解到Notepad2&…

《动手学习深度学习》笔记(二)线性神经网络

三、线性神经网络 3.1 线性回归 3.1.1 介绍 1. 回归是为一个或多个自变量与因变量之间的关系建模的一类方法。而线性回归基于几个简单的假设&#xff1a;① 自变量和因变量关系是线性的&#xff1b;② 允许包含噪声但是噪声遵循正态分布。   2. 训练数据集/训练集&#xff…

算法训练营 day53 动态规划 买卖股票的最佳时机系列2

算法训练营 day53 动态规划 买卖股票的最佳时机系列2 买卖股票的最佳时机III 123. 买卖股票的最佳时机 III - 力扣&#xff08;LeetCode&#xff09; 给定一个数组&#xff0c;它的第 i 个元素是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。…

软件项目管理知识回顾---网络图

网络图 9.网络图 9.1简介 1.分类 AOA&#xff0c;双代号&#xff0c;ADMAON,PDM&#xff0c;单代号&#xff0c;前导图2.活动的逻辑管理 头到头/尾&#xff0c;尾到头/尾 依赖关系 3.工序 紧前紧后9.2绘制规则 1.两个节点只能一条线。不能是平行线。平行的话就不知道是哪个活动…

LeetCode-93. 复原 IP 地址

目录题目思路回溯法题目来源 93. 复原 IP 地址 题目思路 意识到这是切割问题&#xff0c;切割问题就可以使用回溯搜索法把所有可能性搜出来&#xff0c;和131.分割回文串就十分类似了。 回溯法 1.递归参数 startIndex一定是需要的&#xff0c;因为不能重复分割&#xff0c…

【GeoDjango框架解析】读取矢量数据写入postgis数据库

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 【GeoDjango框架解析】读取矢量数据写入postgis数据库 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录系列…

关于iframe一些通讯的记录(可适用工作流审批,文中有项目实践,欢迎咨询)

一.知识点(1).我们可以通过postMessage(发送方)和onmessage(接收方)这两个HTML5的方法, 来解决跨页面通信问题&#xff0c;或者通过iframe嵌套的不同页面之间的通信a.父页面代码如下<div v-if"src" class"iframe"><iframeref"iframe"id…

Kafka进阶篇-消费者详解Flume消费Kafka原理

简介 由于挺多时候如果不太熟系kafka消费者详细的话&#xff0c;很容易产生问题&#xff0c;所有剖析一定的原理很重要。 Kafka消费者图解 消费方式 消费者总体工作流程 消费者组初始化流程 消费者详细消费流程 消费者重要参数 bootstrap.servers 向 Kafka 集群建立初…

Jackson使用进阶

实现 注解 属性命名 JsonProperty 定义属性序列化时的名称。 JacksonAnnotation public interface JsonProperty {public final static String USE_DEFAULT_NAME "";public final static int INDEX_UNKNOWN -1;//指定属性的名称。String value() default USE_…

2022IDEA搭建springMvc项目

springmvc项目搭建一. 创建maven项目二. Add Framework Support三. 添加依赖并配置maven四. 配置前端控制器DispatcherServlet五. 配置SpringMVC.XML文件六. 创建controller类七. 创建index.html页面八. 查看jar包是否添加九. 配置tomcat&#xff08;重&#xff09;十. springm…

Kafka(7):生产者详解

1 消息发送 1.1 Kafka Java客户端数据生产流程解析 1 首先要构造一个 ProducerRecord 对象,该对象可以声明主题Topic、分区Partition、键 Key以及值 Value,主题和值是必须要声明的,分区和键可以不用指定。 2 调用send() 方法进行消息发送。 3 因为消息要到网络上进行传输…

国产蓝牙耳机什么便宜又好用?学生党平价蓝牙耳机推荐

蓝牙耳机凭借近几年的快速发展&#xff0c;越来越多的品牌、款式出现在人们的日常生活当中。最近看到很多人问&#xff0c;国产蓝牙耳机什么便宜又好用&#xff1f;针对这个问题&#xff0c;我来给大家推荐几款平价蓝牙耳机&#xff0c;很适合学生党&#xff0c;一起来看看吧。…

推荐系统从入门到入门(3)——基于MapReuduce与Spark的分布式推荐系统构建

本系列博客总结了不同框架、不同算法、不同界面的推荐系统&#xff0c;完整阅读需要大量时间&#xff08;又臭又长&#xff09;&#xff0c;建议根据目录选择需要的内容查看&#xff0c;欢迎讨论与指出问题。 目录 系列文章梗概 系列文章目录 三、MapReduce 1.MapReduce详…

赶紧收藏:如何使用Telegram客户支持

想要使用Telegram需要客户支持&#xff1f;您需要了解的有关使用Telegram作为客户服务渠道的所有信息&#xff0c;本文章都会介绍。我们将首先讨论提供Telegram支持以及入门所需了解的内容。然后&#xff0c;我们将向您展示如何用智能客服工具ss可以帮助您提供一流的服务Telegr…

Oracle监听详解

本文摘自《ORACLE数据库技术实用详解》和《成功之路&#xff1a;ORACLE 11g学习笔记》 配置网络环境 本文将介绍和Oracle相关的网络问题&#xff0c;Oracle网络建立在操作系统之上。配置操作系统网络是配置Oracle网络的第一步。在配置Oracle网络之前&#xff0c;我们需要确保操…

数学基础--均值、方差、标准差、协方差

1. 简介 统计学中最核心的概念之一是&#xff1a;标准差及其与其他统计量&#xff08;如方差和均值&#xff09;之间的关系&#xff0c;本文将对标准差这一概念提供直观的视觉解释&#xff0c;在文章的最后我们将会介绍协方差的概念。 2. 概念介绍 均值 均值&#xff1a; 均值…

(一)Spring-Cloud源码分析之核心流程关系及springcloud与springboot包区别(新)

文章目录1. 前言2. springcloud简介3. Springcloud包简介4. Springcloud和Springboot流程关系5. Springcloud启动流程新增的功能和接口5.1 新增接口5.2 新增功能类5.2.1 spring-cloud-context包5.2.2 spring-cloud-commons包6. Springcloud实现机制带来的问题7. Springcloud和S…

【MyBatis】映射器配置|注解完成CRUD(三)

&#x1f697;MyBatis学习第三站~ &#x1f6a9;起始站&#xff1a;MyBatis概述&环境搭建(一) &#x1f6a9;本文已收录至专栏&#xff1a;数据库学习之旅 &#x1f44d;希望您能有所收获 上一篇我们学习了如何使用Mapper代理开发&#xff0c;核心配置文件&#xff0c;但却…