搜索算法特训 ----- Week5/6/7 (它太重要了)

news2024/11/18 1:35:43

学会二叉树不知道干啥?二叉树的深度优先搜索和广度优先搜索,我要打十个乃至二十个(打开你的LeetCode撸起来)学练并举_二叉树广度优先搜索_小杰312的博客-CSDN博客

上述文章,初步介绍了搜索过程和关于二叉树中进行搜索的很多实例。将搜索的过程写的还是很详细的。很有套路性。学会可以很明了整个搜索的过程。 但是对搜索算法的认知深度和层次还不够。还不够下细。很多细节之处的打磨还不够。所以今日,再次基础之上,希望可以将细节打磨的更加到位。加深自身对于搜索算法的认知。以及增强递归代码书写的可控性。

认知:

搜索算法题目 (广度, 深度, 记忆化)

  • 搜索的本质是什么? 状态树展开遍历的过程中根据题意寻找目标结点.
  • 搜索的过程总是从初始状态展开的过程.
  • 从搜索过程中就形成了一棵以初始状态为根节点、包含所有可能到达目标状态的路径的状态树。

搜索的方式/策略多种多样. 但是本质正是一种遍历, 遍历的过程中排除不要的。寻求并且留下要的。

找到要的就可以开始返回。携带着题目要求信息返回. 

  • 注意1: 既然是遍历, 我们需要做到不重不漏.
  • 注意2: 递归中传值暗含着回溯. 天然的可以回到之前的特性。但是切记, 传参时&引用可以打破这种天然的回溯  (递归的本质是深搜)
  • 注意3: 递归调用的看待 (不要单纯看作一层函数, 而是看作一个套娃盲盒. 不知道多少层的盲盒)
  • 注意4: 把握好递归函数的返回, 时机(返回条件) 和 顺序, 位置缺一不可.

递归最难最难的是什么?

  • 最难最难的其实不是做题. 而是不受掌控的做题.

初练递归题目的时候, 相信大家都会心生如此感受, 题目做出来了。但是感觉很模糊,
只是凭借着大量的肌肉记忆做出来了。我会做了。但是不是所有的递归题目我都有把握。
如果状态好可能就AC了,状态不好,可能就会一直卡在那里,知道大致思路,但是难以递归实现。

通过有思路, 有方向性的训练来培养对递归代码的掌控程度?

  • 递归函数参数的设计性 (常规:当前状态, 目标状态, 引用&携带返回信息)
  • 参数可以增加搜索的限制条件
  • 返回值设计性:返回值也可携带返回信息.
  • 终止条件的设计性. (返回的位置)
  • 终止条件:success search ans and failure search ans.

从最天然的递归结构 --- 树(初步感受递归dfs(深度搜索))

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

力扣

怎么做 ? 先用我们正常人是思想思考。如果我们都从下向上走。5 和 1分别向上上去之后第一个交汇点就是答案。       

转换:思想很简单了。我们找到了两个目标结点之后,向上走。走到第一个交汇就是答案。

1. 怎么找到目标结点。  (搜索) 

2. 怎么知道已经找到目标结点。(判断。靠什么判断。回去的的时候带点东西来判断:记住。判断,没别的,如果是回溯的时候判断子树是否搜索到目标,用的就是返回值。最好用。参数虽然也可。但是麻烦。)  

3. 怎么向上的.   (回溯,递归回溯的时候天然的状态回退)

4. 怎么判断交汇. (左边通知上来一个目标,右路也通知上来一个目标)

5. 怎么将交汇时候的答案结点返回。(看如何设计了。究竟是全局?还是局部返回?还是参数带出?)

Coding  递归代码。最具精简,应该要非常体现每一步的可读性。简洁易懂,明了清晰。如果那一步的意图不清楚,说明这个题目的AC是运气,而非实力。

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root == nullptr) return nullptr;
        // 找到q或者p 返回.
        if (root->val == p->val || root->val == q->val) return root;
        // 递归展开. 套娃深入. 并且用lchild rchild 拿到左右路回溯上来的结果
        TreeNode* lchild = lowestCommonAncestor(root->left, p, q);
        TreeNode* rchild = lowestCommonAncestor(root->right, p, q);
        //交汇点。ans所在处
        if (lchild && rchild) return root; 
        //交汇点之前和之后, 携带搜索目标和答案返回. so do this
        if (lchild || rchild) return lchild != nullptr ? lchild : rchild;
        return nullptr;//找不到
    }
};

上述代码获得了正确的答案。但是我的思路是存在问题的。是存在致命缺陷的。

我只考虑了从左右两路同时上来交汇于一处。但是我没有考虑一路上来。Waht? 什么意思?没错,就是存在一个结点即是题目要求结点本身。但是也是交汇结点的情况。

我携带着错误的思想写出的第一版错误代码:一直没有通过,卡在这里:错误代码如下:

class Solution {
    TreeNode* ans;
    bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root == nullptr) return 0;
        // 找到q或者p 返回.
        if (root->val == p->val || root->val == q->val) {
            return 1;
        }
        // 递归展开. 套娃深入. 并且用lchild rchild 拿到左右路回溯上来的结果
        bool lSearchAns = dfs(root->left, p, q);
        bool rSearchAns = dfs(root->right, p, q);
        //交汇点。ans所在处
        if (lSearchAns && rSearchAns) {
            ans = root;
            return 0;// 反正只有一组答案. 找到之后剩下的都不能是ans了.
        } 
        //将这一路的结果带回
        if (lSearchAns || rSearchAns) return 1;
        return 0;//找不到
    }

public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root == nullptr) return nullptr;
        dfs(root, p, q);
        return ans;
    }
};

上述代码几乎完全就是最上面代码的翻版。但是很遗憾第二款代码是错误的。我很庆幸。写了第二版错误代码。发现了自己思维的缺陷。

其实就仅仅只是return ,还有一处return 或许是有问题的。那就是找到q或者p的返回。如果我在此处添加ans = root; 便可以如愿AC.

 

        // 找到q或者p 返回.   OR may be, return ans?  what? p OR q maybe just equal ans. 哈哈哈。。。    需要考虑。q 和 p本身就是交汇点。这是我初次做这个题目没有思考到的。虽然但是还是莫名其妙AC。但是这就是递归。

        if (root->val == p->val || root->val == q->val) return root;

递归设计的艺术:我们需要整体的解决问题的一个格局。一个整体的流程。先从最简单的问题解决本身入手。思考需要些什么。需要的东西在那个阶段。处理的先后顺序。。。

处理逻辑(收集每一层最大值OR遍历收集特定结点...) + 处理阶段 (递归深入阶段)  OR (递归回溯阶段)       回溯阶段。专门对应了一种算法。叫做回溯... 也是特别重要。特别适合路径收集.

答案收集的阶段性

力扣

124. 二叉树中的最大路径和

力扣 

又是一道很经典的题目。题目很经典,难度就看看。不管难不难,我们学习算法嘛。最好深入思路。题目逻辑,细节考虑的难度。我们就慢慢积累。

分析: 路径就是连在一起的多个结点序列。然后结点不可重复。 路径起点不一定是根部。然后找最大路径和。有意思。这个题目搞明白,深度优先搜索,递归过程理解,回溯阶段理解都可以更加深刻了.

这个路径,完全随意呀。只要是连着的几个结点,起点任意。不交叉重复就OK.  

 

观察我画的这个图:什么意思。答案可能不一定在上边。答案可能就在下面。

我们必须搞清楚的是:最大的路径结果,可能是左子树独立,右子树独立,又或者是左子树,根部,右子树,拼接在一起,左子树拼接根部,右子树拼接根部,均可能. 

class Solution {
    int ans;    
    int dfs(TreeNode* root) {
        if (root == nullptr) return 0;
        //获取左右子树路径最大值. 可跟根部拼接的最值
        int lsum = dfs(root->left);
        int rsum = dfs(root->right);
        
        //可能的答案收集, 左子树+根部, 右子树+根部. 单独根部. 左子树+根部+右子树
        //因为选择是最优子路径, 所以左右子树不可舍弃. 绝对>0
        ans = max(ans, lsum+root->val);
        ans = max(ans, rsum+root->val);
        ans = max(ans, root->val);
        ans = max(ans, lsum+root->val+rsum);

        //选择和上面根部拼接的最优子路径
        int retval = max(lsum+root->val, rsum+root->val);
        retval = max(retval, 0);
        retval = max(retval, root->val);
        return retval;
        
    }
public:
    int maxPathSum(TreeNode* root) {
        ans = INT_MIN;
        dfs(root);
        return ans;
    }
};

此题难点在于细节多,思路思考清楚之后就是一些细节处理了。思路就是左子树,右子树,左右子树根部何在一块,都有可能产生答案.

递归参数设计性

力扣

分析题目:啥叫作堂兄弟,这是我们需要抓住的重点,证明是堂兄弟需要哪些关键信息. 深度相同,说明是同一辈的,老爹不同,说明是堂兄弟.

 咋做捏?  两个办法? 深度相同,其实也就是同一层嘛,可以用广度搜索。广度搜索就是那种一面面,一层层,一圈圈的处理。我的感觉就是一种原点扩散。一个原点向外一圈一圈,一层一层的展开。这个就是广度嘛。因为是按照一定的距离,或者权重绕着起点扩散搜索的。所以距离是慢慢扩大的。同一层距离最开始的位置都是一个间距。我靠。说开了。这么一说。其实层序后面的理论都说完了。

不过这个题目,我还是想用深搜去做。不论别的,提高递归参数,返回值。。。设计能力。  我最开始的适合说过,参数其实是用于携带条件信息的。或者做传出参数,相当于返回值。当然,此处的爹爹必须携带。不然,我们咋晓得是不是一个爹?  自然深度相同,我们还需要携带回来深度。深度可以用返回值带回来。

OK. 开搞,这个自然是需要搜索两次了。非常的明显,一次搜索可能应该我是没办法实现的。此处的parent因为传入的是& 所以,每次在递归调用之前,需要我们手动进行parent的设置.

class Solution {
    int dfs(TreeNode* root, int x, TreeNode*& parent) {
        if (root == nullptr) return -1; //null深度设置为-1, 没找到
        if (root->val == x) return 0;//找到了返回
        parent = root;//设置parent
        int ldeep = dfs(root->left, x, parent);
        if (ldeep != -1) return ldeep+1;
        parent = root;//回溯, 设置parent
        int rdeep = dfs(root->right, x, parent);
        if (rdeep != -1) return rdeep+1;
        return -1;
    }

public:
    bool isCousins(TreeNode* root, int x, int y) {
        if ( root == nullptr) return false;
        TreeNode* parentx = nullptr, *parenty = nullptr;
        int deepx = dfs(root, x, parentx);
        int deepy = dfs(root, y, parenty);
        return parentx != parenty && deepx == deepy;
    }
};

        int ldeep = dfs(root->left, x, parent);
        if (ldeep != -1) return ldeep+1;
        parent = root;//回溯, 设置parent
        int rdeep = dfs(root->right, x, parent);
        if (rdeep != -1) return rdeep+1;

我有一个疑问:上述代码,可否改成如下:

        int ldeep = dfs(root->left, x, parent);
        parent = root;//回溯, 设置parent
        int rdeep = dfs(root->right, x, parent);

        if (ldeep != -1) return ldeep+1;
        if (rdeep != -1) return rdeep+1;

完全不能,错误,绝对的错误,我第一次就是这样错的,属于什么错误? 返回位置,返回时机控制出现问题。ldeep判断了之后,应该立刻。马上返回。我都傻逼了。不晓得自己咋会写成下面那个傻逼代码。。。   

注意:已经找到目标值之后。   回溯阶段parent不做任何修改。

再来一道参数设计的题目:用三种方式设计参数解决它。让大家再次感受下递归函数参数的设计性.

 

力扣

思路:我知道,这道题最合适的就是广搜。为啥?最低?最小?广搜适合解决最短路径,一切具备最小的距离的那种搜索问题。

但是老实讲。广搜太具有模板性了。所以这个题目我们用深搜来做岂不锻炼自己.

/**
 * 二叉树的最小深度。很明显最简单的方式就是层序了
 * 一层层向下,出现没有孩子结点的结点自然就是最小深度层的叶子结点
 * 
 * 解法 a. 采取的方式是利用无参深度优先搜索
 class Solution {
    int ans = INT_MAX;//记录结果
    void dfs(TreeNode* root, int deep) {
        if (root == nullptr) return;
        if (root->left == nullptr && root->right == nullptr) {//maybe ans
            ans = min(deep, ans);
            return;
        }
        dfs(root->left, deep+1);
        dfs(root->right, deep+1);
        return;
    }

public:
    int minDepth(TreeNode* root) {
        if (root == nullptr) return 0;
        dfs(root, 1);
        return ans;
    }
};
 * 
 *
 * 体现递归函数参数返回值设计性的时候来了.
class Solution {
    //利用返回值获取结果.
    int dfs(TreeNode* root, int deep) {
        if (root == nullptr) return INT_MAX;//说明不是结果.
        if (root->left == nullptr && root->right == nullptr) {
            return deep;//maybe ans;
        }
        int ldeep = dfs(root->left, deep+1);
        int rdeep = dfs(root->right, deep+1);
        return min(ldeep, rdeep);
    }

public:
    int minDepth(TreeNode* root) {
        if (root == nullptr) return 0;
        return dfs(root, 1);
    }
}; 
 * 
 *递归函数参数的设计。有些时候就是区分是真的学懂递归过程的时候.
 * class Solution {
    //利用入参返回结果.
    void dfs(TreeNode* root, int deep, int& ans) {
        if (root == nullptr) return;
        if (root->left == nullptr && root->right == nullptr) {
            ans = min(ans, deep);
            return;
        }
        dfs(root->left, deep+1, ans);
        dfs(root->right, deep+1, ans);
        return;
    }

public:
    int minDepth(TreeNode* root) {
        if (root == nullptr) return 0;
        int ans = INT_MAX;
        dfs(root, 1, ans);
        return ans;
    }
};
*/

三种版本的代码放在这里了。经过上面个的题目打磨。这题,要解决小case.

广度优先搜索 --- 最自然的搜索策略

广度搜索就是那种一面面,一层层,一圈圈的处理。我的感觉就是一种原点扩散。一个原点向外一圈一圈,一层一层的展开。这个就是广度嘛。因为是按照一定的距离,或者权重绕着起点扩散搜索的。所以距离是慢慢扩大的。同一层距离最开始的位置都是一个间距。我靠。说开了。这么一说。其实层序后面的理论都说完了。

广度优先搜索的理论特别的简单。但是他确实一种特别实用的搜索策略。或者遍历策略。最短路径从策略。如果我的感觉没有错误。他跟Dijkstra算法有那么一点异曲同工之妙。 只不过Dijkstra算的是权重不是1. 所以不能简单的使用队列来维护这个顺序。需要用到heap堆结构。或者说带权重的队列。优先队列来维护这些结点的搜索,最短路径展开。

Dijkstra理论:

Dijkstra算法根据当前已知的最短路径长度来选择下一个要探索的节点,该选择基于贪心策略:每次选择当前距离起始节点最近的未探索节点。

与BFS相比,Dijkstra算法在以下方面应用了广度优先搜索的思想:

  1. 探索顺序:Dijkstra算法按照节点到起始节点的距离递增的顺序进行探索,这与BFS按层级顺序探索的思想相似。

  2. 路径更新:在Dijkstra算法中,如果找到了更短的路径来到达某个节点,它会更新该节点的最短路径长度。这类似于BFS在发现更短路径时更新节点的距离。

总之吧:Dijskra和广度优先搜索算法联合起来学习。这个确实可以理解的更为轻松方便。两者有着异曲同工,给我的感觉都是有点贪心的意思。贪心的觉得目的地就应该在自己附近。最近的位置上。  区别:

然而,Dijkstra算法与BFS也存在一些关键的区别:

  1. 优先级队列:Dijkstra算法使用优先级队列(通常使用最小堆)来选择下一个要探索的节点。这使得它能够根据节点到起始节点的距离进行有效的选择。而BFS则使用FIFO队列,只按照节点的到达顺序进行探索。

  2. 权重边:Dijkstra算法考虑了图中边的权重,它通过不断更新节点的最短路径长度来找到最短路径。而BFS通常用于无权图或每条边权重相同的情况。

题目:

力扣

102. 二叉树的层序遍历 (算法很单纯,一道足够了)

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> ans;
        if (root == nullptr) return ans;
        queue<TreeNode*> que;
        TreeNode* p = nullptr;
        que.push(root);//入0层结点
        //每一层结点都放进去, 全部放进去
        int deep = 0;
        while (!que.empty()) {
            ans.push_back(vector<int>());//给一层盖房子
            int n = que.size();
            for (int i = 0; i < n; i++) {
                p = que.front(); que.pop();
                ans[deep].push_back(p->val);
                if (p->left) que.push(p->left);
                if (p->right) que.push(p->right);
            }
            deep += 1;//下一层
        }
        return ans;
    }
};

经典的回溯

学习方向:别的不说。一张纸,一支笔,一个空数组,1,2,3.按照不同的情况往里面放置一次,感受感受。这不比直接撸代码强。代码录得再多,终究会忘记。回溯最重视过程。请大家拿起笔和纸,充当人型递归机器。走一步。这特别对于排列组合,回溯问题的解决比啥都强。因为它们都是路径问题呀。这个路径咋走的。我们需要做到心中有数。

46. 全排列
https://leetcode.cn/problems/permutations/description/

77. 组合
https://leetcode.cn/problems/combinations/description/

47. 全排列 II
https://leetcode.cn/problems/permutations-ii/description/

39. 组合总和
https://leetcode.cn/problems/combination-sum/description/

78. 子集
https://leetcode.cn/problems/subsets/description/

90. 子集 II
https://leetcode.cn/problems/subsets-ii/description/

二维矩阵中的广搜与深搜

学习方向:本质还是回溯问题。所以上面的那些题目做完之后,心中对于回溯已经有所认知了。有所认知的基础之下,实践。再认知,再实践。算法。数据结构的学习要有迭代性。

细节点注意:有些适合题目里面有坑,需要提前做个预处理啥的。比如把边上的陆地变成海水呀。啥的。总之,注意细节。方法绝对就那两种搜索。重要的是细节的处理。

经典的二维矩阵的深度搜索

200. 岛屿数量
https://leetcode.cn/problems/number-of-islands/

1020. 飞地的数量
https://leetcode.cn/problems/number-of-enclaves/description/

695. 岛屿的最大面积
https://leetcode.cn/problems/max-area-of-island/description/

37. 解数独
https://leetcode.cn/problems/sudoku-solver/description/

52. N 皇后 II
https://leetcode.cn/problems/n-queens-ii/description/

22. 括号生成
https://leetcode.cn/problems/generate-parentheses/#/description


二维矩阵的广度优先搜索典型例题:

934. 最短的桥
https://leetcode.cn/problems/shortest-bridge/description/

搜索算法的核心就在于在遍历搜索空间所有状态的过程收集特定的路径或者状态的过程。几乎无数算法的基础。如果是一道大家都没有做过的题目,我想大家拿到手上的第一个想法应该都是思考遍历。穷举。在穷举的过程中发现可以利用某一算法思想或是某一快速查找的数据结构对时间复杂度进行降阶。       比如单纯的搜索 + 记忆化 + 状态积累。(动态规划)        单纯的线性查找 + hash表或者红黑树可以实现  O(1) 或者是 O(logN) 的查找时间复杂度降阶.....  种种迹象,无一不在重复着搜索算法以及穷举思想的重要性.     

最好,跟兄弟们建个议,您读了我的文章就是个缘分。哈哈哈。小杰不喜欢被规矩卡死的,天马行空学习的大学生活。但是也不能荒废。学计算机嘛。积累积累积累大过一切。一切东西,当我们的基础深度足够的适合都变得轻松易懂了起来。

算法数据结构学习小心得:会忘,且很快,解决办法,就把自己的一些总结当作数学公式,反复。反复的是那个思路,不是那段代码。最好,祝看见这篇文章的兄弟工作的升职加薪,身体健康,学习的学业进步,保研高校。拜拜。咯,算法,暂时这一阶段就到这里了。哈哈哈,下一步,希望可以学习一些工程项目能力,对C++的各种语法糖做一些应用,写一些小框架,小轮子,为未来做打算,做沉淀。                                       ----   

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

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

相关文章

网站出现卡顿是什么原因,要怎么解决?

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言网站卡顿的原因解决…

人工智能算法在外卖配送系统中的应用和前景

随着人们对于外卖服务需求的增加&#xff0c;外卖配送系统的效率和精确度成为了重要的考虑因素。而人工智能算法的出现&#xff0c;则为外卖配送系统提供了更好的解决方案。 一、应用场景 1.1 路线规划 在外卖配送过程中&#xff0c;路线的规划是非常重要的。通过人工智能算…

一线大厂最全Java面试题及答案整理汇总(2023最新版)

程序员一步入中年&#xff0c;不知不觉便会被铺天盖地的“危机感”上身&#xff0c;曾经的那个少年已经不在&#xff0c;时间就是这样公平。就算你能发明 Java 语言&#xff0c;随着时间的推移&#xff0c;你注定还是要成为慢慢变蔫的茄子&#xff0c;缓缓变黑的葡萄。 看着金…

uniapp 自定义发行 动态修改 manifest.json

这边需求是&#xff1a;根据不同的打包环境 设置不同的标题以及路径。方便各种调试。防止 每次手动每次修改 manifest.json 出错 uniapp 自定义发行: 添加自定义发行之后 Hbuilder 编辑器会自动多 出来按钮&#xff1a; 官方文档&#xff1a;概述 | uni-app官网 我这里的配置是…

大数据开发基础-环境配置篇-Hadoop集群安装

鼠鼠接下来将更新一系列自己在学习大数据开发过程中收集的资源、和自己的总结、以及面经答案、LeetCode刷题分析题解。 首先是大数据开发基础篇 环境搭建、组件面试题等 其次是更新大数据开发面经的java面试基础 最后更新一个大数据开发离线数仓的实战项目&#xff0c;自己写入…

利用R中的corrmorant包绘制精美的相关性热图

大家好&#xff0c;我是带我去滑雪&#xff01; 相关性热图 (correlation heatmap) 是一种可视化工具&#xff0c;用于展示数据集中各个变量之间的相关性。它以矩阵的形式显示变量之间的相关系数&#xff0c;并通过色彩编码来表示相关性的强度。在相关性热图中&#xff0c;每个…

html面试题-概念题汇总

文章目录 html面试题汇总 src和href的区别 HMTL的全局属性有哪些&#xff1f; 超链接访问过后hover样式就不出现的原因是什么&#xff1f;怎么解决&#xff1f; 表单中readonly和disabled属性的区别&#xff1f; iframe的优缺点&#xff1f; 浏览器渲染页面的过程 viewport属性…

GO channel解析

GO channel解析 是什么&#xff1f; 官方文档&#xff1a; https://go.dev/ref/spec#Channel_typeshttps://go.dev/blog/pipelines&#xff08;channel提供了流式编程的例子&#xff09; 在 Go 语言中&#xff0c;channel 是一种用于在 goroutine 之间进行通信和同步的机制。…

【FFmpeg实战】音频解码与编码流程

解码流程 音频编解码流程与视频编解码流程一致&#xff0c;我们可以对 mp4 文件的音频流进行解码&#xff0c;并将解码后的音频数据保存到 PCM 文件中&#xff0c;后续我们可以通过读取 PCM 文件中的数据实现音频流的编码操作 FFmpeg音频解码流程 extern"C" { #inc…

ICC2: Create Placement Blockage

area-based的placement blockage有四种,hard、hard macro、soft,partial。hard 属性限制所有standard cell、hard macro放进hard blockage中;hard macro仅限制hard macro(如sram);soft属性限制placement的init_place阶段(也叫coarse placement)把standard cell和hard macro…

Vuex学习

5.1.理解 Vuex 5.1.1.Vuex 是什么 概念&#xff1a;专门在Vue中实现集中式状态&#xff08;数据&#xff09;管理的一个Vue插件&#xff0c;对Vue应用中多个组件的共享状态进行集中式的管理&#xff08;读/写&#xff09;&#xff0c;也是一种组件间通信的方式&#xff0c;且适…

深度学习05-CNN循环神经网络

概述 循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一种具有循环连接的神经网络结构&#xff0c;被广泛应用于自然语言处理、语音识别、时序数据分析等任务中。相较于传统神经网络&#xff0c;RNN的主要特点在于它可以处理序列数据&#xf…

超全汇总,性能测试常用指标大全(重要)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 两种性能指标 业…

Java又双叒叕“凉”了?

前几天&#xff0c;TIOBE的一份6月编程语言榜单公布&#xff1a;Java退出前三&#xff0c;位居第四。一波Java凉了的言论甚嚣尘上。其实不止Java&#xff0c;python、C、C&#xff0c;哪一个没被提过“凉”... 而现实是&#xff0c;Java的招聘需求依然很大&#xff1a; 不可否…

C++静态和动态链接库导出和使用

1、简介 代码开发过程中会遇到很多已有的函数库&#xff0c;这些函数库是现有的&#xff0c;成熟的&#xff0c;可以复用的代码。现实中每个程序都要依赖很多基础的底层库&#xff0c;不可能每个人的代码都从零开始&#xff0c;因此库的存在意义非同寻常。 本质上来说库是一种…

便携式水质自动采样器助力毒情监测

便携式水质自动采样器可助力毒情监测&#xff1a; 污水涉毒采样检测工作是运用科技手段准确评估监测辖区内毒情形势的重要手段。期间&#xff0c;民警详细了解了生活和工业污水的处理、排放以及服务范围、人口数量等情况&#xff0c;并就污水涉毒采样检测工作达成共识。随后&am…

revit中用幕墙来绘制瓦片屋面和生成土钉墙

一、revit中用幕墙来绘制瓦片屋面 层层叠叠的瓦片在我们绘制时具有复杂性&#xff0c;瓦片既美观又满足一些建筑的需要&#xff0c;下面教大家一个用幕墙来绘制瓦片屋面。 新建一个族样板选择公制轮廓—竖挺&#xff0c;绘制我们的瓦片形状 简单的绘制一个瓦片的形状&#xff0…

JVM学习整理(一)

一、JVM的基本介绍 JVM 是 Java Virtual Machine 的缩写&#xff0c;它是一个虚构出来的计算机&#xff0c;一种规范。通过在实际的计算机上仿真模拟各类计算机功能实现 好&#xff0c;其实抛开这么专业的句子不说&#xff0c;就知道JVM其实就类似于一台小电脑运行在windows或…

ruoyi-vue前后端分离项目实现一体化打包(前后端合并打包)

场景 现在要对ruoyi-vue前后端分离项目&#xff0c;进行一体化打包&#xff0c;即 将前后端项目打在一个jar里面 一体化打包优点 不需要再使用nginx&#xff0c;直接将前端文件放到后端项目里面 改造ruoyi-vue项目 后端改造 1、引入依赖spring-boot-starter-thymeleaf &…

倒计时 1 天 | SphereEx 在 2023 亚马逊云科技中国峰会等你来打卡!

2023 年 6 月 27 - 28 日&#xff0c; “因构建而可见” 2023 亚马逊云科技中国峰会将在上海隆重举行&#xff0c;SphereEx 将携面向新一代数据架构的数据库增强引擎&#xff1a;SphereEx-DBPlusEngine 亮相亚马逊云科技中国峰会&#xff0c;展示分布式数据库、数据安全、信创替…