代码随想录 -- 回溯算法

文章目录

  • 回溯算法理论
    • 什么是回溯法
    • 回溯法的效率
    • 回溯法解决的问题
    • 理解回溯法
    • 回溯法模板
  • 组合问题I
    • 描述
    • 题解
    • 优化
  • 组合总和III
    • 描述
    • 题解
  • 电话号码的字母组合
    • 描述
    • 题解
  • 组合总和
    • 描述
    • 题解
  • 组合总和II
    • 描述
    • 题解
  • 分割回文串
    • 描述
    • 题解
  • 复原IP地址
    • 描述
    • 题解
  • 子集
    • 描述
    • 题解
  • 子集II
    • 描述
    • 题解
  • 递增子序列
    • 描述
    • 题解
  • 全排列
    • 描述
    • 题解
  • 全排列 II
    • 描述
    • 题解
  • 重新安排行程 难
    • 描述
      • 如何处理死循环?
      • 映射关系的记录
    • 题解
  • N皇后 难
    • 描述
    • 题解
  • 解数独 跳过
    • 描述
    • 题解

回溯算法理论

什么是回溯法

回溯法也可以叫做回溯搜索法,它是一种搜索的方式。

回溯是递归的副产品,只要有递归就会有回溯。

回溯法的效率

纯暴力搜索

虽然回溯法很难,很不好理解,但是回溯法并不是什么高效的算法。
因为回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法高效一些,可以加一些剪枝的操作,但也改不了回溯法就是穷举的本质。

回溯法解决的问题

  • 组合问题:N个数里面按一定规则找出k个数的集合
  • 切割问题:一个字符串按一定规则有几种切割方式
  • 子集问题:一个N个数的集合里有多少符合条件的子集
  • 排列问题:N个数按一定规则全排列,有几种排列方式
  • 棋盘问题:N皇后,解数独等等

理解回溯法

回溯法解决的问题都可以抽象为树形结构

因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度,都构成的树的深度。

递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。

回溯法模板

伪代码

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

组合问题I

题目链接

描述

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

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

题解

class Solution {
private:
    vector<vector<int>>res;//最后的结果
    vector<int>path;//放单个组合
    
    void backtracking(int n,int k,int startIndex){
        if (path.size()==k){
            res.push_back(path);
            return;
        }
        for (int i = startIndex; i <= n; ++i) {
            path.push_back(i);
            backtracking(n,k,i+1);//使用递归代表for 一层递归一个for循环
            path.pop_back();
        }
    }
public:
    // 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合
    vector<vector<int>> combine(int n, int k) {
        backtracking(n,k,1);
        return res;
    }
};

优化

如果n=k=4 那么第一层for循环从i=2之后都毫无意义

可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。

如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了。

优化过程

  • 已经存入的元素的个数:path.size()
  • 还需要的元素的个数:k-path.size()
  • 表中剩余元素的个数:n-i >= 所需元素(k - path.size())
  • 在集合n中至多要从该起始位置 : i <= n - (k - path.size()) + 1,开始遍历
    为什么有个+1呢,因为包括起始位置,我们要是一个左闭的集合。

举个例子,n = 4,k = 3, 目前已经选取的元素为0(path.size为0),n - (k - 0) + 1 即 4 - ( 3 - 0) + 1 = 2。
从2开始搜索都是合理的,可以是组合[2, 3, 4]。

class Solution {
private:
    vector<vector<int>>res;//最后的结果
    vector<int>path;//放单个组合
    
    void backtracking(int n,int k,int startIndex){
        if (path.size()==k){
            res.push_back(path);
            return;
        }
        for (int i = startIndex; i <= n-(k-path.size())+1; ++i) {//优化后的for循环
            path.push_back(i);
            backtracking(n,k,i+1);//使用递归代表for 一层递归一个for循环
            path.pop_back();
        }
    }
public:
    // 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合
    vector<vector<int>> combine(int n, int k) {
        backtracking(n,k,1);
        return res;
    }
};

组合总和III

题目链接

描述

找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

说明:

所有数字都是正整数。
解集不能包含重复的组合。
示例 1: 输入: k = 3, n = 7 输出: [[1,2,4]]

示例 2: 输入: k = 3, n = 9 输出: [[1,2,6], [1,3,5], [2,3,4]]

题解

class Solution {
private:
    vector<vector<int>> res;
    vector<int> path;

    /**
     *
     * @param k 1-9之间选取的个数
     * @param n k个数的和为n
     * @param startIndex 循环开始的数
     * @param sum 目前已经和为多少
     */
    void backtracking(int k, int n, int startIndex, int sum) {
        if (sum > n)return;
        if (path.size() == k) {
            if (sum == n)res.push_back(path);
            return; // 如果path.size() == k 但sum != targetSum 直接返回
        }
        for (int i = startIndex; i <= 9 - (k - path.size()) + 1; ++i) {// 剪枝
            path.push_back(i);
            sum += i;
            backtracking(k, n, i + 1, sum);
            path.pop_back();
            sum -= i;
        }
    }

public:
    vector<vector<int>> combinationSum3(int k, int n) {
        path.clear();
        res.clear();
        backtracking(k, n, 1, 0);
        return res;
    }
};

电话号码的字母组合

题目链接

描述

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

在这里插入图片描述
输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
说明:尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

题解

class Solution {
private:
    vector<string> res;
    string path;
    vector<string>flags={"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    void backtracking(string digits,int len,int startIndex) {
        if (path.size()==len){
            res.push_back(path);
            return;
        }
        string letter=flags[digits[startIndex]-'0'-2];
        for (int i = 0; i < letter.size(); ++i) {
            path.push_back(letter[i]);
            backtracking(digits,len,startIndex+1);
            path.pop_back();
        }
    }

public:
    vector<string> letterCombinations(string digits) {
        int len = digits.size();
        if (!len)return res;
        backtracking(digits,len,0);
        return res;
    }
};

组合总和

题目链接

描述

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:

所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:

输入:candidates = [2,3,6,7], target = 7,
所求解集为: [ [7], [2,2,3] ]
示例 2:

输入:candidates = [2,3,5], target = 8,
所求解集为: [ [2,2,2,2], [2,3,3], [3,5] ]

题解

class Solution {
private:
    vector<vector<int>> res;
    vector<int> path;

    void backtracking(vector<int> &canidates, int target, int nowSum, int startIndex) {
        if (nowSum > target)return;
        if (nowSum == target) {
            res.push_back(path);
            return;
        }
        int len = canidates.size();
        for (int i = startIndex; i < len; ++i) {
            path.push_back(canidates[i]);
            nowSum += canidates[i];
            backtracking(canidates, target, nowSum, i);
            path.pop_back();
            nowSum -= canidates[i];
        }
    }

public:
    vector<vector<int>> combinationSum(vector<int> &candidates, int target) {
        backtracking(candidates, target, 0, 0);
        return res;
    }
};

组合总和II

添加链接描述

描述

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

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

说明: 所有数字(包括目标数)都是正整数。解集不能包含重复的组合。

示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]

题解

class Solution {
private:
    vector<vector<int>>res;
    vector<int>path;
    void backtracking(vector<int>&candidates,int target,int nowSum,int index){
        if (nowSum>target)return;
        if (nowSum==target){
            res.push_back(path);
            return;
        }
        for (int i = index; i < candidates.size(); ++i) {
            if (i>index&&candidates[i]==candidates[i-1])continue;
            path.push_back(candidates[i]);
            nowSum+=candidates[i];
            backtracking(candidates,target,nowSum,i+1);
            path.pop_back();
            nowSum-=candidates[i];
        }

    }
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(),candidates.end());
        backtracking(candidates,target,0,0);
        return res;
    }
};

分割回文串

题目链接

描述

给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。

返回 s 所有可能的分割方案。

示例: 输入: “aab” 输出: [ [“aa”,“b”], [“a”,“a”,“b”] ]

题解

class Solution {
private:
    vector<vector<string>>res;
    vector<string>path;
    bool isPalindrome(const 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;
    }
    void backtracking(const string&s,int startIndex){
        // 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
        if (startIndex>=s.size()){
            res.push_back(path);
            return;
        }

        for (int i = startIndex; i < s.size(); ++i) {
            if (isPalindrome(s,startIndex,i)){
                // 获取[startIndex,i]在s中的子串
                string str=s.substr(startIndex,i-startIndex+1);
                path.push_back(str);
            }else//如果不是回文串 那么跳过
                continue;
            backtracking(s,i+1);
            path.pop_back();
        }
    }
public:
    vector<vector<string>> partition(string s) {
        backtracking(s,0);
        return res;
    }
};

复原IP地址

题目链接

描述

给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。

有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 ‘.’ 分隔。

例如:“0.1.2.201” 和 “192.168.1.1” 是 有效的 IP 地址,但是 “0.011.255.245”、“192.168.1.312” 和 “192.168@1.1” 是 无效的 IP 地址。

示例 1:

输入:s = “25525511135”
输出:[“255.255.11.135”,“255.255.111.35”]
示例 2:

输入:s = “0000”
输出:[“0.0.0.0”]
示例 3:

输入:s = “1111”
输出:[“1.1.1.1”]

题解

class Solution {
private:
    vector<string> res;
    // startIndex: 搜索的起始位置,pointNum:添加逗点的数量
    void backtracking(string &s, int startIndex, int pointNum) {
        if (pointNum == 3) {//逗号个数为3时 分割结束
            //判断第四段字符串是否合法
            if (vaildIP(s, startIndex, s.size() - 1)) {
                res.push_back(s);
                return;
            }
        }

        for (int i = startIndex; i < s.size(); ++i) {
            if (vaildIP(s, startIndex, i)) {// 判断 [startIndex,i] 这个区间的子串是否合法
                s.insert(s.begin() + i + 1, '.');//在i后面插入逗号
                ++pointNum;
                backtracking(s, i + 2, pointNum);
                --pointNum;
                s.erase(s.begin() + i + 1);
            } else break;//不合法直接结束本层循环 因为如果这一段不合法那么再加一个字符也是不合法的
        }
    }

    bool vaildIP(const string &s, int start, int end) {
        if (start > end)return false;
        if (s[start] == '0' && start != end)return false;

        int num=0;
        for (int i = start; i <= end; ++i) {
            if (s[i]<'0'||s[i]>'9')return false;
            num=num*10+s[i]-'0';
            if (num>255)return false;
        }
        return true;
    }

public:
    vector<string> restoreIpAddresses(string s) {
        backtracking(s, 0, 0);
        return res;
    }
};

子集

题目链接

描述

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例: 输入: nums = [1,2,3] 输出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]

题解

class Solution {
private:
    vector<vector<int>>res;
    vector<int>subSet;
    void backtracking(vector<int>&nums,int startIndex){
        res.push_back(subSet); // 收集子集,要放在终止添加的上面,否则会漏掉自己
        if (startIndex>=nums.size())return;//终止条件 可以不加,因为下面的循环当startIndex==size的时候就不会进行了
        for (int i = startIndex; i < nums.size(); ++i) {
            subSet.push_back(nums[i]);
            backtracking(nums,i+1);
            subSet.pop_back();
        }
    }
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        backtracking(nums,0);
        return res;
    }
};

子集II

题目链接

描述

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

说明:解集不能包含重复的子集。

示例:

输入: [1,2,2]
输出: [ [2], [1], [1,2,2], [2,2], [1,2], [] ]

题解

和子集I思路差不多,不过多了一个去重操作

class Solution {
private:
    vector<vector<int>>res;
    vector<int>path;

    void backtracking(vector<int>&nums,int startIndex){
        res.push_back(path);
        if (startIndex>=nums.size())return;
        for (int i = startIndex; i < nums.size(); ++i) {
            if (i>startIndex&&nums[i]==nums[i-1])continue;
            path.push_back(nums[i]);
            backtracking(nums,i+1);
            path.pop_back();
        }
    }
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        backtracking(nums,0);
        return res;
    }
};

递增子序列

题目链接

描述

给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。

示例:

输入: [4, 6, 7, 7]
输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]
说明:

给定数组的长度不会超过15。
数组中的整数范围是 [-100,100]。
给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况。

题解

有更好的优化 比如unordered_set换成数组 因为题目给出了数字的范围

class Solution {
private:
    vector<vector<int>> res;
    vector<int> path;

    void backtracking(vector<int> &nums, int startIndex) {
        if (path.size() >= 2) {
            res.push_back(path);
            //后面不可以加return 因为要遍历全部
        }
        unordered_set<int> uset;//uset仅负责一层 也就是一层递归调用函数
        for (int i = startIndex; i < nums.size(); ++i) {
            if (!path.empty() && nums[i] < path.back() || uset.find(nums[i]) != uset.end())
                continue;
            uset.insert(nums[i]);//记录本层本元素已经使用 不影响下一层 (下一次递归)
            path.push_back(nums[i]);
            backtracking(nums, i + 1);
            path.pop_back();
        }
    }

public:
    vector<vector<int>> findSubsequences(vector<int> &nums) {
        backtracking(nums, 0);
        return res;
    }
};

全排列

题目链接

描述

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]

题解

排列问题:

  • 每层都是从0开始搜索而不是startIndex
  • 需要used数组记录path里都放了哪些元素了
class Solution {
private:
    vector<vector<int>> res;
    vector<int> path;

    void backtracking(vector<int> &nums,vector<bool>&used) {
        if (path.size() == nums.size()) {
         // 此时说明找到了一组
            res.push_back(path);
            return;
        }

        for (int i = 0; i < nums.size(); ++i) {
            if (used[i])continue;// path里已经收录的元素,直接跳过
            used[i]=true;
            path.push_back(nums[i]);
            backtracking(nums,used);
            used[i]=false;
            path.pop_back();
        }
    }

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

全排列 II

题目链接

描述

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]
输出: [[1,1,2], [1,2,1], [2,1,1]]
示例 2:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
提示:

1 <= nums.length <= 8
-10 <= nums[i] <= 10

题解

借用代码随想录网站的图:

树层上去重(used[i - 1] == false),的树形结构如下:
在这里插入图片描述
树枝上去重(used[i - 1] == true)的树型结构如下:
在这里插入图片描述

class Solution {
private:
    vector<vector<int>> res;
    vector<int> path;

    void backtracking(vector<int> &nums, vector<bool> &used) {
        if (path.size() == nums.size()) {
            res.push_back(path);
            return;
        }

        for (int i = 0; i < nums.size(); ++i) {
            // used[i - 1] == true,说明同一树枝nums[i - 1]使用过
            // used[i - 1] == false,说明同一树层nums[i - 1]使用过
            // 如果同一树层nums[i - 1]使用过则直接跳过
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false)continue;
            if (!used[i]) {
                used[i] = true;
                path.push_back(nums[i]);
                backtracking(nums, used);
                path.pop_back();
                used[i] = false;
            }
        }
    }

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

重新安排行程 难

题目链接

描述

给定一个机票的字符串二维数组 [from, to],子数组中的两个成员分别表示飞机出发和降落的机场地点,对该行程进行重新规划排序。所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。

提示:

如果存在多种有效的行程,请你按字符自然排序返回最小的行程组合。例如,行程 [“JFK”, “LGA”] 与 [“JFK”, “LGB”] 相比就更小,排序更靠前
所有的机场都用三个大写字母表示(机场代码)。
假定所有机票至少存在一种合理的行程。
所有的机票必须都用一次 且 只能用一次。
示例 1:

输入:[[“MUC”, “LHR”], [“JFK”, “MUC”], [“SFO”, “SJC”], [“LHR”, “SFO”]]
输出:[“JFK”, “MUC”, “LHR”, “SFO”, “SJC”]
示例 2:

输入:[[“JFK”,“SFO”],[“JFK”,“ATL”],[“SFO”,“ATL”],[“ATL”,“JFK”],[“ATL”,“SFO”]]
输出:[“JFK”,“ATL”,“JFK”,“SFO”,“ATL”,“SFO”]
解释:另一种有效的行程是 [“JFK”,“SFO”,“ATL”,“JFK”,“ATL”,“SFO”]。但是它自然排序更大更靠后。

本题中存在的几个难点

如何处理死循环?

在这里插入图片描述
出发机场和到达机场也会重复的,如果在解题的过程中没有对集合元素处理好,就会死循环

映射关系的记录

题目要求:如果有多个路径,字母序靠前排在前面

一个机场映射多个机场,多个机场之间要按照字母序排序

可以使用unordered_map<string,map<string,int>> targets ,也就是对应

map/set 自动排序(按照数字、字母序,从小到大排序)

unordered_map<出发机场,map<到达机场,航班次数>>

在遍历 unordered_map<出发机场, map<到达机场, 航班次数>> targets的过程中,可以使用"航班次数"这个字段的数字做相应的增减,来标记到达机场是否使用过了

如果“航班次数”大于零,说明目的地还可以飞,如果“航班次数”等于零说明目的地不能飞了,而不用对集合做删除元素或者增加元素的操作。

题解

class Solution {
private:
    unordered_map<string, map<string, int>> targets;
    vector<string> result;

    // 对于本题目而言 我们不需要遍历跟到节点的所有可能,只需要找到一个行程,就是在树形结构中唯一的一条通向叶子节点的路线
    // 所以需要返回值
    bool backtracking(vector<vector<string>> &tickets, int ticketNum) {
        if (ticketNum + 1 == result.size())return true;
        for (pair<const string, int> &target: targets[result[result.size() - 1]]) {
            if (target.second) {
                result.push_back(target.first);
                target.second--;
                if (backtracking(tickets, ticketNum))return true;
                target.second++;
                result.pop_back();
            }
        }
        return false;
    }

public:
    vector<string> findItinerary(vector<vector<string>> &tickets) {
        for (const vector<string> &ticket: tickets)
            targets[ticket[0]][ticket[1]]++;

        result.push_back("JFK");
        backtracking(tickets, tickets.size());
        return result;
    }
};

N皇后 难

题目链接

描述

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

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

不能同行
不能同列
不能同斜线

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
在这里插入图片描述

题解

class Solution {
private:
    vector<vector<string>>res;
    bool isValid(int row,int col,int n,vector<string>&path){
        //检查列
        for(int i = 0; i < row; ++i)
            if(path[i][col]=='Q')return false;
        /* 检查行是多余的,
            因为在单层搜索的过程中,每一层递归,只会选for循环(也就是同一行)里的一个元素,所以不用去重了。
        for(int i = 0;i < col;++i)
            if(path[row][i]=='Q')return false;   
        */
       //45度
       for(int i = col-1,j=row-1;i >= 0&&j>=0;--i,--j){
            if(path[j][i]=='Q')return false;
       }

       //135度
       for(int i = row-1,j=col+1;i>=0&&j<n ;--i,++j){
            if(path[i][j]=='Q')return false;
       }
       return true;

    }
    void backtracking(int n,int start,vector<string>&path){
        if(start==n){
            res.push_back(path);
            return;
        }

        for(int i = 0 ;i < n ;++i){
            if(isValid(start,i,n,path)){
                path[start][i]='Q';
                backtracking(n,start+1,path);
                path[start][i]='.';
            }
        }
    }
public:
    vector<vector<string>> solveNQueens(int n) {
        vector<string>path(n,string(n,'.'));
        backtracking(n,0,path);
        return res;
    }
};

解数独 跳过

题目链接

描述

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

一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 空白格用 ‘.’ 表示。
在这里插入图片描述

在这里插入图片描述
提示:

给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。

题解

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux 学习笔记(16)

十六、 计划任务 在很多时候为了自动化管理系统&#xff0c;我们都会用到计划任务&#xff0c;比如关机&#xff0c;管理&#xff0c;备份之类的操作&#xff0c;我 们都可以使用计划任务来完成&#xff0c;这样可以是管理员的工作量大大降低&#xff0c;而且可靠度更好。 l…

软件测试之学习测试用例的设计(等价类法、边界值法、错误猜测法、场景法、因果图法、正交法)

1. 测试用例的概念 软件测试人员向被测试系统提供的一组数据的集合&#xff0c;包括 测试环境、测试步骤、测试数据、预期结果 2. 为什么在测试前要设计测试用例 测试用例是执行测试的依据 在回归测试的时候可以进行复用 是自动化测试编写测试脚本的依据 衡量需求的覆盖率…

通过简单的案例入门Mybatis~

目录 一.概述 二.JDBC的缺点 三.案例 1.创建测试类 2.加载Mybatis核心配置文件获取SqlSessionFactory 3.获取SqlSession对象 4.执行sql 5.释放资源 一.概述 Mybatis是一款持久层框架&#xff0c;用于简化JDBC开发。所谓框架&#xff0c;就是一个半成品软件&#xff0c;…

2024年【P气瓶充装】考试资料及P气瓶充装考试总结

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年P气瓶充装考试资料为正在备考P气瓶充装操作证的学员准备的理论考试专题&#xff0c;每个月更新的P气瓶充装考试总结祝您顺利通过P气瓶充装考试。 1、【多选题】CNG双燃料汽车系统主要包括&#xff08;&#xff…

数据链路层_以太网

IP协议确定数据跨网络从主机A到主机B的路径&#xff0c;即IP协议解决了路径选择问题&#xff0c;但在这之前&#xff0c;必须先解决数据在一个子网内的传输的问题。跨网络的本质就是跨多个子网&#xff0c;只要一个子网内可以通信&#xff0c;那么便可以跨网络通信。 一.以太…

Echarts+Vue 首页大屏静态示例Demo 第四版 支持自适应

效果: 源码: <template><ScaleScreenclass="scale-wrap":selfAdaption="true":autoScale="true":class="{ fullscreen-container: isFullScreen }"><div class="bg"><dv-loading v-if="loading&…

Docker 中 MySQL 的部署与管理

目录 一、Docker 中部署 MySQL1.1 部署 MySQL1.2 进入容器并创建数据库1.3 Navicat 可视化工具连接 二、可能存在的问题2.1 1130 - Host ‘172.17.0.1‘ is not allowed to connect to this MySQL server 参考资料 一、Docker 中部署 MySQL 1.1 部署 MySQL 首先&#xff0c;从…

[题解]无厘头题目——无聊的军官

这道题非常无厘头&#xff01; 题目描述&#xff1a; 每个学年的开始&#xff0c;高一新生们都要进行传统的军训。今年有一个军训教官十分奇怪&#xff0c;他为了测试学员们的反应能力&#xff0c;每次吹哨后学员们都会变换位置。每次左数第I位学员都会站到第ai个位置&#x…

代码随想录训练营Day25:● 216.组合总和III ● 17.电话号码的字母组合

216.组合总和III 题目链接 https://leetcode.cn/problems/combination-sum-iii/description/ 题目描述 思路 自己写的效率会慢一些&#xff0c;而且没有用到剪枝 class Solution {List<List<Integer>> list new ArrayList<>();List<Integer> lis…

python知识点总结(一)

这里写目录标题 一、什么是WSGI,uwsgi,uWSGI1、WSGI2、uWSGI3、uwsgi 二、python中为什么没有函数重载&#xff1f;三、Python中如何跨模块共享全局变量?四、内存泄露是什么?如何避免?五、谈谈lambda函数作用?六、写一个函数实现字符串反转&#xff0c;尽可能写出你知道的所…

『scrapy爬虫』05. 使用管道将数据写入mysql(详细注释步骤)

目录 1. 新建管道类,并启用2. 准备好mysql数据库新建表3. 实现管道写入数据库的代码测试一下 总结 欢迎关注 『scrapy爬虫』 专栏&#xff0c;持续更新中 欢迎关注 『scrapy爬虫』 专栏&#xff0c;持续更新中 如果对mysql和python不熟悉可看专栏【Python之pymysql库学习】 1.…

Java学习笔记------常用API(四)

BigDecima 用于小数的精准计算 用来表示很大的小数 构造方法获取BigDecimal对象 public BigDecimal(double val)//有可能不精确&#xff0c;不建议使用 public BigDecimal(String val) 静态方法获取BigDecimal对象 public static BigDecimal valueOf(double val)//超出do…

布隆过滤器原理及应用场景

目录 一、布隆过滤器概述1.1 什么是布隆过滤器1.2 优缺点 二、布隆过滤器原理2.1 布隆过滤器的组成2.2 元素添加和查询 三、 应用场景参考资料 一、布隆过滤器概述 1.1 什么是布隆过滤器 布隆过滤器&#xff08;Bloom Filter&#xff09;是一种数据结构&#xff0c;用于快速检…

口腔管理平台 |基于springboot框架+ Mysql+Java+B/S结构的口腔管理平台 设计与实现(可运行源码+数据库+lw文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 管理员功能登录前台功能效果图 会员功能 系统功能设计 数据库E-R图设计 lunwen参考…

五连杆机构运动学仿真 | Matlab源码 | 机械连杆 | 五杆机构

【程序简介】&#x1f4bb;&#x1f50d; 本程序通过matlab实现了五连杆机构的运动学仿真编程&#xff0c;动态展现了五连杆机构的运动动画。 你将获得&#xff1a;五连杆机构Matlab仿真源码 获取地址&#xff1a;五连杆机构运动学仿真 | Matlab源码 |机械连杆 程序仿真的五…

2024年【危险化学品经营单位主要负责人】新版试题及危险化学品经营单位主要负责人复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【危险化学品经营单位主要负责人】新版试题及危险化学品经营单位主要负责人复审考试&#xff0c;包含危险化学品经营单位主要负责人新版试题答案和解析及危险化学品经营单位主要负责人复审考试练习。安全生产模…

Pulsar从入迷到入魔之路

一、引言 系统学习Pulsar的大纲 二、正文 下图是我绘制的Pulsar大纲 (由于时间缘故花的比较粗糙&#xff0c;这张图会不定期更新) 三、学习大纲 一、Pulsar Client 二、生产者 Pulsar消息路由深入剖析 三、消费者 四、Topic pulsar原来是这样操作topic的 五、Funct…

PS学习 - 抠图-通道-主题颜色和背景颜色不能相近

抠出蝴蝶 1.通道抠图 套索工具 这里需要圈住你要的&#xff0c;注意尽量小点 ctrl j 复制 然后去掉背景 点击通道 找到明暗对比最大的通道&#xff0c;这里我理解为颜色反差最大的那个&#xff0c;突出你要抠的东西 搜了下说是一般为蓝色 复制通道 ctrll调出色阶 通过移…

RabbitMQ学习总结-延迟消息

1.死信交换机 一致不被消费的信息/过期的信息/被标记nack/reject的信息&#xff0c;这些消息都可以进入死信交换机&#xff0c;但是首先要配置的有私信交换机。私信交换机可以再RabbitMQ的客户端上选定配置-dead-letter-exchange。 2.延迟消息 像我们买车票&#xff0c;外卖…

llamma笔记:部署Llama2

1 申请Llama2 许可 Download Llama (meta.com) 地址似乎不能填中国 1.1 获取url 提交申请后&#xff0c;填的那个邮箱会受到一封meta发来的邮件&#xff0c;打码部分的url&#xff0c;之后会用得上 2 ubuntu/linux 端部署Llama2 2.1 git clone Llama2的github 仓库 bash g…