基础算法(六):回溯算法

news2024/11/27 18:43:05

前言

        Hello大家好,停了半个多月算法学习的荔枝又变菜了,最近决定认认真真地重新学习回溯,无意间看到Carl哥的代码随想录,感动之余也是跟着一步步走,后悔上车晚了呜呜呜~~~。之前自己摸索确实有点难受,在这篇文章中,荔枝也准备仔仔细细梳理相关的问题和知识点,大家加油💪💪💪


文章目录

前言

一、回溯算法

二、组合问题

2.1 Leecode 77——组合

2.2 Leecode 40——组合总和||

三、切割问题

Leecode 131——分割回文串

四、子集问题

4.1 Leecode 78——子集 

4.2 LeeCode 90——子集||

五、排列问题

 5.1 LeeCode 46——全排列

六、棋盘问题

6.1 LeeCode 51——N皇后

6.2 LeeCode 37——解数独

总结


一、回溯算法

        回溯算法其实是我们接触最多的算法之一,作为暴力算法的代表,回溯算法解决了K重for循环无法键入的问题。同时,回溯算法也体现在所有的递归算法逻辑中,毕竟递归其实本质上就是递推+回溯。回溯的理解其实我们可以抽象为恢复现场,也就是当你选择某种枚举或者是搜索方式来寻找路径的时候,其余的同级选择的遍历前一定会通过回溯算法来实现恢复现场。回溯算法在OJ中的经典题型主要有五类问题需要我们全部掌握:组合问题、切割问题、子集问题、排列问题和棋盘问题。

回溯算法的解题步骤:

  • 确定backtrack回溯函数的参数和返回值
  • 确定边界条件,也就是回溯的终止条件
  • 确定单层回溯函数内For循环的逻辑

解题模板: 

//解题模板--一般来说设置为无返回值void
void backtrack(确定参数){
    if(终止条件){
        ...
        return;
    }
    //确定单层for循环逻辑
    for(...){
        ...
    }
}

二、组合问题

2.1 Leecode 77——组合

 

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

示例 1:

输入:n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

        组合问题的demo跟荔枝上面的答题模板很相像是不哈哈哈,回溯算法最经典的地方就是在组合问题, 思路其实很简单:当我们顺序遍历题目中的元素,如果v容器的大小达到题目要求就会被收集到结果result中,每一次调用递归函数之后都需要进行回溯操作回退到前一层,更换不同可能的路径选择。

demo示例: 

class Solution {
private:
    vector<vector<int>> result;
    vector<int> v;
    void back(int n,int k,int index){
        if(v.size()==k){
            result.push_back(v);
            return;
        }
        for(int i=index;i<=n;i++){
            v.push_back(i);
            back(n,k,i+1);
            v.pop_back();
        }
    }
public:
    vector<vector<int>> combine(int n, int k) {
        // 一道非常经典的回溯算法题目
        back(n,k,1);
        return result;
    }
};

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/combinations/

看起来组合问题也不是很难呐哈哈哈,接下来看一道稍微难一点的:

2.2 Leecode 40——组合总和||

题目描述:

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意:解集不能包含重复的组合。 

输入示例:

candidates = [10,1,2,7,6,1,5], target = 8,

输出示例:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

        由于输入数组中有重复的元素,因此我们需要在一开始将输入的数组进行排序,排序的目的是为了更好地去重。而对于去重的规则,我们使用了一个used数组来记录元素的使用情况,对于一个重复的元素,经过排序之后我们知晓相同的元素一定相邻,当我们i-1和i是重复的时候,选择i就会产生重复的组合,这是因为在i-1树枝上我们已经将i的情况全部遍历过了,因此当used[i-1]==used[i]&&used[i-1]==0时的情况应该被去重。 其余的递归回溯过程其实都跟模板是一样的!

demo示例:

class Solution {
private:
    vector<vector<int>> result;
    vector<int> v;
    void back(vector<int>& candidates,int target,int sum,int index,vector<bool>& used){
        // 确定终止条件
        if (sum > target) {
            return;
        }
        if(sum == target){
            result.push_back(v);
            return;
        }
        for(int i=index;i<candidates.size();i++){
            // 去重
            if(i>0 && candidates[i]==candidates[i-1] && used[i-1]==0){
                continue;
            }
            v.push_back(candidates[i]);
            used[i] = true;
            back(candidates,target,sum+candidates[i],i+1,used);
            used[i] = false;
            v.pop_back();
        }
    }
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        if(candidates.size()==0){
            return result;
        }
        // 排序
        vector<bool> used(candidates.size(), false);
        sort(candidates.begin(), candidates.end());
        back(candidates,target,0,0,used);
        return result;
    }
};

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/combination-sum-ii/


三、切割问题

        切割问题,其实也可以看成是组合问题的另一种表述,当我们确定分割的规则,利用index来记住我们同一树层的遍历次序。

Leecode 131——分割回文串

题目描述:

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案(回文串是正着读和反着读都一样的字符串)。

输入示例:

s = "aab"


输出示例:

[["a","a","b"],["aa","b"]]

        对于分割问题,每一个for循环就是在横向遍历同一树层的元素,递归的过程就是纵向的遍历树枝值,那么对于上一层切好的index,我们遍历i的取值来实现下一层的切割选择,所以[index,i]就是我们当次递归切割出来的子串,需要判断该子串是否是回文串,如果是就证明我们没切错。

demo示例:

class Solution {
private:
    vector<vector<string>> result;
    vector<string> v;
    void strSplit(string s,int index){
        if(index>=s.size()){
            result.push_back(v);
        }
        for(int i=index;i<s.size();i++){
            if(isTure(s,index,i)){
                string str = s.substr(index, i - index + 1);
                v.push_back(str);
            }else{
                continue;
            }
            strSplit(s,i+1);
            v.pop_back();
        }
    }
    //双指针法判断回文串
    bool isTure(string s,int start,int end){
        for(int i = start, j = end; i < j; i++, j--){
            if(s[i]!=s[j]) return false;
        }
        return true;
    }
public:
    vector<vector<string>> partition(string s) {
        if(s.length()==1){
            v.push_back(s);
            result.push_back(v);
            return result;
        }
        strSplit(s,0);
        return result;
    }
};

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/palindrome-partitioning


四、子集问题

4.1 Leecode 78——子集 

题目描述:

给你一个整数数组 nums ,数组中的元素互不相同。返回该数组所有可能的子集(幂集)。

解集不能包含重复的子集。你可以按任意顺序返回解集。

输入示例:

[1,2,3]

输出示例:

[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

子集问题相比于组合问题不同点在于它的递归函数收取结果的地方不止在叶子节点,而是所有符合要求的节点都属于该问题的子集,因此我们每进入递归函数的时候就开始收集结果。

class Solution {
private:
    vector<int> v;
    vector<vector<int>> result;
    void back(vector<int>& nums,int index){
        result.push_back(v);
        //边界条件
        if(index >= nums.size()) return;
        for(int i=index;i<nums.size();i++){
            v.push_back(nums[i]);
            back(nums,i+1);
            v.pop_back();
        }
    }
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        back(nums,0);
        return result;
    }
};

 题目来源:力扣(LeetCode)
链接: https://leetcode.cn/problems/subsets/

4.2 LeeCode 90——子集||

题目描述:

给你一个整数数组 nums ,其中可能包含重复元素,返回该数组所有可能的子集(幂集)。

解集不能包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

输入示例:

[1,2,2]

输出示例:

[[],[1],[1,2],[1,2,2],[2],[2,2]] 

        子集||相比于子集在输入数组中增加了重复元素,因此我们需要使用一个数组used来标记同一层元素的使用情况,跟组合问题一样的去重规则,同样的在去重之前还是需要利用sort来使相同的元素排列相邻方便去重。

demo示例: 

class Solution {
private:
    vector<vector<int>> result;
    vector<int> v;
    void back(vector<int>& nums,int index,vector<bool>& used){
        result.push_back(v);
        for(int i=index;i<nums.size();i++){
            if(i > 0 && nums[i] == nums[i-1] && used[i-1] == false){
                continue;
            }
            v.push_back(nums[i]);
            used[i] = true;
            back(nums,i+1,used);
            used[i] = false;
            v.pop_back();
        }
    }

public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        if(nums.size()==0){
            return result;
        }
        vector<bool> used(nums.size(), false);
        sort(nums.begin(),nums.end());
        back(nums,0,used);
        return result;
    }
};

题目来源:力扣(LeetCode)
链接: https://leetcode.cn/problems/subsets-ii/


五、排列问题

排列问题和组合问题的最大的不同就是排列中是由顺序的,简单来说就是[1,2]和[2,1]是两种不同的结果。接下来我们来看看有重复元素和无重复元素的全排列问题的解法。

 5.1 LeeCode 46——全排列

题目描述:

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

输入示例:

[1,2,3]

输出示例:

[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

        排列问题其实跟组合问题很像,最大的不同就是排列问题不再会有index来记录遍历的元素,并且增加了一个used数组用来记录输入数组中所有元素的使用状态。在排列问题中我们会使用所有的数组元素,因此只要结果集中的数组长度等于输入数组的长度即可达到边界条件。 

demo示例:

class Solution {
private:
    vector<vector<int>> result;
    vector<int> v;
    void backtrack(vector<int>& nums,vector<bool>& used){
        //确定回溯截止条件
        if(v.size()==nums.size()){
            result.push_back(v);
        }
        //确定单层回溯的规则
        for(int i=0;i<nums.size();i++){
            if(used[i]){
                continue;
            }
            used[i] = true;
            v.push_back(nums[i]);
            backtrack(nums,used);
            v.pop_back();
            used[i] = false;
        }

    }
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<bool> used(nums.size(),false);
        backtrack(nums,used);
        return result;
    }
};

题目来源:力扣(LeetCode)
链接: https://leetcode.cn/problems/permutations/

 那如果输入的数组中有重复元素,我们应该如何处理呢?

我们来看看Leecode中的全排列||

跟组合问题一样,我们在最开始对输入数组中的元素进行排序,并利用used数组来帮助我们去重,去重的规则和组合问题相比也是一样的。

class Solution {
private:
    vector<vector<int>> result;
    vector<int> v;
    void backtrack(vector<int>& nums,vector<bool>& used){
        //确定回溯截止条件
        if(v.size()==nums.size()){
            result.push_back(v);
        }
        //确定单层回溯的规则
        for(int i=0;i<nums.size();i++){
            if(used[i] || (i-1>=0 && nums[i-1] == nums[i] && used[i-1]==false)){
                continue;
            }
            used[i] = true;
            v.push_back(nums[i]);
            backtrack(nums,used);
            v.pop_back();
            used[i] = false;
        }

    }
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<bool> used(nums.size(),false);
        sort(nums.begin(),nums.end());
        backtrack(nums,used);
        return result;
    }
};

题目来源:力扣(LeetCode)
链接: https://leetcode.cn/problems/permutations-ii/


六、棋盘问题

        棋盘问题算是回溯算法种难度比较高的问题了,这里的难度其实并不是难在过程有多么复杂,主要是当我们用回溯算法模板刷爆前面的组合、切割、子集和排列问题后我们已经习惯处理一维容器的问题了,在棋盘问题中我们首先来看看最经典的N皇后问题:

6.1 LeeCode 51——N皇后

题目描述

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

输入示例:

4

输出示例:

[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]

        我们仔细来看看题目,题目对于皇后的放置是由要求的,也就是同一行、同一列、同一45度或者是135度的直线上不能同时存在两个及以上的皇后。 空的格子使用‘.’来表示,放置皇后的格子用‘Q’来表示。那么对于一个棋盘来说,我们的递归对象就是对棋盘上的每一行,for循环遍历对象是每一行上的元素,我们在下面封装了一个校验皇后放置的规则的函数isVaild(),当规则允许的时候我们就放置皇后并递推和回溯,直到触发边界条件:递归到了棋盘的边界。而关于判断皇后位置正误的逻辑其实很简单,手动画一个棋盘推一下就好了哈哈哈,这里荔枝给出一个图来辅助理解吧:

 

demo示例:

class Solution {
private:
    vector<vector<string>> result;
    void backtrack(vector<string>& chessboard,int n,int row){
        if(row==n){
            result.push_back(chessboard);
        }
        for(int i=0;i<n;i++){
            if(isVaild(row,i,chessboard,n)){
                chessboard[row][i] = 'Q';
                backtrack(chessboard,n,row+1);
                chessboard[row][i] = '.';
            }
        }
    }
    bool isVaild(int row,int col,vector<string>& chessboard,int n){
        // 对列上的皇后情况进行去除
        for(int i=0;i<row;i++){
            if(chessboard[i][col]=='Q'){
                return false;
            }
        }
        // 对左上方也就是135度方向进行皇后去除
        for(int i=row-1,j=col-1;i>=0 && j>=0;i--,j--){
            if(chessboard[i][j]=='Q'){
                return false;
            }
        }
        // 对右上方也就是45度方向进行皇后去除
        for(int i=row-1,j=col+1;i>=0 && j<n;i--,j++){
            if(chessboard[i][j]=='Q'){
                return false;
            }
        }
        return true;
    }
public:
    vector<vector<string>> solveNQueens(int n) {
        vector<string> chessboard(n,string(n,'.'));
        backtrack(chessboard,n,0);
        return result;
    }
};

看完这份代码其实大家可以看到其实N皇后问题也是用到了荔枝上面使用的题解模板,所以有了答题模板后的我们,确实强大了不少哈哈哈哈。

题目来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/n-queens

6.2 LeeCode 37——解数独

题目描述:

编写一个程序,通过填充空格来解决数独问题。

数独的解法需 遵循如下规则:

  • 数字 1-9 在每一行只能出现一次。
  • 数字 1-9 在每一列只能出现一次。
  • 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

数独部分空格内已填入了数字,空白格用 '.' 表示。

输入示例:

[["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]]

 

输出示例:

[["5","3","4","6","7","8","9","1","2"],["6","7","2","1","9","5","3","4","8"],["1","9","8","3","4","2","5","6","7"],["8","5","9","7","6","1","4","2","3"],["4","2","6","8","5","3","7","9","1"],["7","1","3","9","2","4","8","5","6"],["9","6","1","5","3","7","2","8","4"],["2","8","7","4","1","9","6","3","5"],["3","4","5","2","8","6","1","7","9"]]

        这道题目相较于前面的N皇后问题最大的不同点就在于它是采用三层for来实现调用递归函数的过程的,由于题目的特殊要求,我们需要遍历数独矩阵中的每一个位进行查询改为上有没有数字,同时遍历数字1-9来看看同行、同列以及同一个九宫格中有没有重复的元素。整段代码的结构和之前相比其实没有什么大的区别。

demo示例:

class Solution {
private:
    bool backtrack(vector<vector<char>>& board){
        for(int i=0;i<board.size();i++){
            for(int j=0;j<board[0].size();j++){
                if(board[i][j]=='.'){
                    for(char k='1';k<='9';k++){
                        if(isValid(i,j,k,board)){
                            board[i][j] = k;
                            if(backtrack(board)) return true;
                            board[i][j] = '.';
                        }
                    }
                    return false;
                }
            }
        }
        return true;
    }
    bool isValid(int row,int col,char str,vector<vector<char>>& board){
        // 判断行里有没有重复的元素
        for(int i = 0;i<9;i++){
            if(board[row][i] == str){
                return false;
            }
        }
        // 判断列里面有没有重复元素
        for(int j = 0;j<9;j++){
            if(board[j][col]==str){
                return false;
            }
        }
        // 判断一个9方格种有没有重复的元素
        int startRow = (row/3)*3;
        int startCol = (col/3)*3;
        for(int i = startRow; i < startRow+3; i++){
            for(int j = startCol; j < startCol+3; j++){
                if(board[i][j]==str){
                    return false;
                }
            }
        }
        return true;
    }
public:
    void solveSudoku(vector<vector<char>>& board) {
        backtrack(board);
    }
};

题目来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/sudoku-solver


总结

        在这篇文章中,荔枝主要通过回溯算法的模板题解来类比回溯算法五大问题:组合、分割、子集、排列和棋盘问题,通过上述的代码我们发现其实一个模板就可以将几乎所有的回溯算法的问题都解决了。总算找到适合自己的刷题方法了,跟着Carl哥给的顺序刷这样收获真的很大哈哈哈哈。希望我的分享也能帮到一起学习的小伙伴嘻嘻嘻嘻。

今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~

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

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

相关文章

YUM安装LNMP架构配置命令与搭建论坛

LNMP架构配置命令与搭建论坛 LNMP简介安装须知安装 Nginx配置yum源yum安装nginx并查看版本号开启服务并且设为开机自启 安装 MySQL 5.7 (mariadb)移除软件包下载安装mysql安装MySQL报错问题解决方案&#xff1a; 开启服务并设为开机自启在日志文件中找出root用户的初始密码登录…

数据结构 --- 树

1、二叉树 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 每个结点最多有两棵子树&#xff0c;即二叉…

CAPL(vTESTStudio) - CAPL控制RS232继电器

目录 为什么要使用CAPL控制继电器? 一、RS232继电器选择 二、继电器通信协议

AList 一个支持多种存储的文件列表程序,使用 Gin 和 Solidjs。

一个支持多种存储&#xff0c;支持网页浏览和 WebDAV 的文件列表程序&#xff0c;由 gin 和 Solidjs 驱动。 特点 使用简单 AList 从一开始就设计为易于安装&#xff0c;并且可以在所有平台上使用。 多种存储 AList 支持多个存储提供商&#xff0c;包括本地存储、阿里云盘、O…

大数据治理入门系列:数据治理

在信息经济时代&#xff0c;数据是企业的一大关键资产。为了制定科学、有效、合理的决策&#xff0c;企业需要收集大量的数据并进行各种数据分析&#xff0c;为决策提供依据。在此过程中&#xff0c;收集数据的速度、数据的质量和可靠性、对数据的分析过程、合适的分析工具等&a…

三十四、数学知识——约数(试除法 + 约数个数 + 约数之和 + 欧几里得算法)

约数相关算法主要内容 一、基本思路1、定义2、试除法——求一个数的所有约数3、约数个数4、约数之和5、欧几里得算法——辗转相除法&#xff08;求解最大公约数&#xff09; 二、Java、C语言模板实现三、例题题解 一、基本思路 1、定义 约数&#xff1a; 约数是指一个数&…

利用百度API进行植物识别

植物识别_拍照识别植物-百度AI开放平台百度AI植物识别,支持识别超过2万种通用植物和近8千种花卉&#xff0c;接口返回植物的名称&#xff0c;并获取百科信息&#xff0c;适用于拍照识图类APP中https://ai.baidu.com/tech/imagerecognition/plant 偶然看到的&#xff0c;不过真…

STM32F103C8T6+2.4寸SPI TFT触摸屏代码+标准库 项目开发

目录 模块清单&#xff1a; 模块介绍&#xff1a; 1&#xff1a;STM32F103C8T6 2&#xff1a;2.4寸SPI TFT触摸屏 项目结果展示 2.4寸 TFT SPI显示触摸屏 2.4寸 SPI TFT 显示触摸屏代码下载链接&#xff1a; (1条消息) 2.4寸SPITFT显示触摸屏资源-CSDN文库 模块清单&#x…

Vue后台管理系统【附源码】

登录 – 完成 路由拦截 – 完成 商品管理&#xff08;增加、编辑、搜索、删除&#xff09; – 完成 角色管理&#xff08;增加、编辑、搜索、删除、权限管理&#xff09; – 完成 交易订单&#xff08;增加、编辑、搜索、删除&#xff09; – 完成 用户管理&#xff08;增加、编…

在Centos Stream 9上Docker的实操教程 - 实操准备篇

在Centos Stream 9上Docker的实操教程 - 实操准备篇 认识Docker准备Centos Stream 9安装Docker更新仓库绕不开的HelloWorld结语 认识Docker 什么都要实操了&#xff0c;你还不知道Docker是什么&#xff1f;网上关于Docker的介绍一搜一大把&#xff0c;博主就不必浪费时间去侃侃…

ESP32-OTA

文章目录 1. 什么是OTA&#xff1f;2. OTA的基本原理3. ESP32远程OTA步骤&#xff1a;3.1 将需要升级的程序放在该目录下3.2 启动HTTP服务器3.3 配置3.4 烧录程序3.5 上电测试ESP32端 4. 问题&#xff1a;5. 通过命令控制OTA6. 参考&#xff1a; 1. 什么是OTA&#xff1f; OTA…

如何用 GPT-4 帮你写游戏(以24点游戏举例)

目录 给我一个24点游戏 游戏规则 GPT给的代码 ​改进 再改进 最近呢掀起了一阵GPT-4的热潮&#xff0c;很多人都想用GPT-4&#xff0c;这里呢我就打一个广告&#xff08;嘿嘿&#xff09;&#xff0c;如果不知道国内如何使用GPT的&#xff0c;可以看看这个博客&#xff1a;G…

STC89C52+DHT20设计的环境温湿度检测仪

一、项目背景 本项目基于STC89C52单片机和DHT20温湿度传感器,实现了一款环境温湿度检测仪。通过传感器采集环境的温度和湿度数据,利用IIC接口的OLED显示屏显示出来,便于用户实时监测环境温湿度状态。 在现代社会,人们对环境温湿度的要求越来越高。无论是工作场所还是居住…

局部特征匹配(LoFTR) 基于全局匹配的光流学习(GMFlow)

文章目录 特征匹配&#xff08;稀疏匹配与稠密匹配&#xff09;《LoFTR: Detector-Free Local Feature Matching with Transformers》【CVPR21】《GMFlow: Learning Optical Flow via Global Matching》【CVPR22】光流的定义第一个问题第二个问题方法该框架下存在的一个问题 Pr…

智慧园区管理平台优势详解

随着数字化和智能化的时代到来&#xff0c;越来越多的园区开始使用智慧园区管理平台来提高管理效率&#xff0c;降低管理成本和提升服务质量。智慧园区管理平台是一种通过智能化技术与物联网技术进行连接&#xff0c;对园区进行综合管理、智能化监控的信息化平台。下面将详细介…

大数据:云平台,阿里云VPC创建,创建安全组,云服务器ECS,

大数据&#xff1a;云平台 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle&#xff0c;尤其sql要学&…

Seata之@GlobalTransactional验证

下订单 -> 减库存 -> 扣余额 -> 改&#xff08;订单&#xff09;状态 1.数据库初始情况&#xff1a; 2.正常下单 http://localhost:2001/order/create?userId1&productId1&count10&money100 3.超时异常&#xff0c;没加GlobalTransactional 模拟Accou…

RabbitMQ系列(24)--RabbitMQ集群搭建

前言&#xff1a;当RabbitMQ服务器遇到内存崩溃、机器掉电或者主板故障等情况&#xff0c;该怎么办?单台RabbitMQ服务器可以满足每秒1000条消息的吞吐量&#xff0c;那如果应用需要RabbitMQ服务满足每秒10万条消息的吞吐量呢?购买昂贵的服务器来增强单机RabbitMQ服务的性能不…

阿里云ECS部署chat-web代理访问

1、ECS服务器申请 使用阿里云账号购买了一个美国&#xff08;弗吉尼亚&#xff09;的2C/2G的CentOS7.9 x64服务器。 2、系统版本升级 CentOS7.9默认的python和pip版本都是3.6的&#xff0c;需要升级到3.9以上&#xff0c;升级步骤百度&#xff0c;大致如下&#xff1a; wget…

vue diff算法与虚拟dom知识整理(12) patch精细化比较新增子节点

上文中我们编写了patch函数中对相同节点的几种处理 将简单的都写完了 但还留下了最麻烦的子节点比较 既新旧节点都有子节点 需要 精细化比较 我们先将src下的入口文件index.js 代码改成这样 import h from "./snabbdom/h"; import patch from "./snabbdom/pat…