[算法和数据结构]--回溯算法之DFS初识

news2024/11/15 20:26:49

回溯算法——DFS

  • DFS介绍(Depth First Search)
  • DFS经典题目
    • 1. 员工的重要性
    • 2. 图像渲染
    • 3.被围绕的区域
    • 4.岛屿数量
    • 5. 电话号码的字母组合
    • 6.数字组合
    • 7. 活字印刷
    • 8. N皇后

DFS介绍(Depth First Search)

  • 回溯法(back tracking)(探索与回溯法)回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。
  • 回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。也可以称为剪枝点,所谓的剪枝,指的是把不会找到目标,或者不必要的路径裁剪掉。
  • DFS算法就是深度优先算法,在数据结构的学习中,二叉树的前序遍历就是属于深度优先算法。

深度优先搜索其实就是一条路走到黑。我们来看一道很经典的DFS题目让我们来了解深度优先搜索。

✨问题描述:

假如有编号为1~ 3的3张扑克牌和编号为1~3的3个盒子,现在需要将3张牌分别放到3个盒子中去,且每个盒子只能放
一张牌,一共有多少种不同的放法

✨ 思路分析:
在这里插入图片描述
上面这张图画出了回溯过程的前半部分,接下来按着深度优先搜索的方式接着进行回溯,我们可以得到剩下的三种情况:
在这里插入图片描述
我们进行上述的深度优先搜索的时候,我们在一个盒子中放扑克牌是从1 – 3号扑克牌依次进行放入的,这样我们可以用for循环搞定。但是我们如何确定该位置要放的扑克牌,是否在前面已经被放过了呢?我们可以使用一个标记数组 int[] book 来记录当前扑克牌在前面是否被放入了。

✨ 代码实现:

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();//盒子和牌的个数
        int[] book = new int[n + 1];
        int[] box = new int[n + 1];
        Dfs(1,book,box,n);
    }

    private static void Dfs(int idx, int[] book, int[] box, int n) {
        if (idx == n + 1){//此时已经完成了一次深度优先搜索
            for (int i = 1; i <= n; i++) {
                System.out.print(box[i] + "  ");
            }
            System.out.println();
            return;
        }

        for (int i = 1; i <= n; i++) {//深度优先搜索,去放置牌
            if(book[i] == 0){
                box[idx] = i;//idx个盒子放第i个牌
                book[i] = 1;//代表第i个牌已经使用了
                Dfs(idx + 1, book, box, n);//处理下一个盒子
                book[i] = 0;//第i张牌重新拿到手里
            }
        }

    }

DFS经典题目

1. 员工的重要性

原题链接

✨问题描述:

给定一个保存员工信息的数据结构,它包含了员工 唯一的 id ,重要度 和 直系下属的 id 。
比如,员工 1 是员工 2 的领导,员工 2 是员工 3 的领导。他们相应的重要度为 15 , 10 , 5 。那么员工 1 的数据结构是 [1, 15, [2]] ,员工 2的 数据结构是 [2, 10, [3]] ,员工 3 的数据结构是 [3, 5, []] 。注意虽然员工 3 也是员工 1 的一个下属,但是由于 并不是直系 下属,因此没有体现在员工 1 的数据结构中。
现在输入一个公司的所有员工信息,以及单个员工 id ,返回这个员工和他所有下属的重要度之和。

✨输入案例:

输入:[[1, 5, [2, 3]], [2, 3, []], [3, 3, []]], 1
输出:11
解释:
员工 1 自身的重要度是 5 ,他有两个直系下属 2 和 3 ,而且 2 和 3 的重要度均为 3 。因此员工 1 的总重要度是 5 + 3 + 3 = 11 。

✨题目分析

该问题就类似于二叉树的前序遍历。从单个员工的重要度开始计算,依次遍历员工的下属,下属有员工再次搜索下属。直到没有下属员工再依次回退查看有没有其他的子员工。
在这里插入图片描述

✨ 解题代码:

    public int getImportance(List<Employee> employees, int id) {
        Map<Integer,Employee> empMap = new HashMap<>();//用哈希表存储数据查找会更方便更快速。
        for (Employee employee: employees) {
            empMap.put(employee.id,employee);
        }
        return DFS(empMap,id);
    }

    private int DFS(Map<Integer, Employee> empMap, int id) {
        int sum = empMap.get(id).importance;//加上该员工的重要度
        for (int curId:empMap.get(id).subordinates) {//该员工有下属就进行for-each循环DFS,没有的话就不进去循环
            sum += DFS(empMap,curId);
        }
        return sum;
    }

2. 图像渲染

原题链接

✨问题描述:

有一幅以 m x n 的二维整数数组表示的图画 image ,其中 image[i][j] 表示该图画的像素值大小。
你也被给予三个整数 sr , sc 和 newColor 。你应该从像素 image[sr][sc] 开始对图像进行 上色填充 。
为了完成 上色工作 ,从初始像素开始,记录初始坐标的 上下左右四个方向上 像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应 四个方向上 像素值与初始坐标相同的相连像素点,……,重复该过程。将所有有记录的像素点的颜色值改为 newColor 。
最后返回 经过上色渲染后的图像 。

✨题目样例:

案例1:
在这里插入图片描述

输入: image = [[1,1,1],[1,1,0],[1,0,1]],sr = 1, sc = 1, newColor = 2
输出: [[2,2,2],[2,2,0],[2,0,1]]
解析: 在图像的正中间,(坐标(sr,sc)=(1,1)),在路径上所有符合条件的像素点的颜色都被更改成2。
注意,右下角的像素没有更改为2,因为它不是在上下左右四个方向上与初始点相连的像素点。

案例2:

输入: image = [[0,0,0],[0,0,0]], sr = 0, sc = 0, newColor = 2
输出: [[2,2,2],[2,2,2]]

✨ 题目分析:

这个题目用DFS算法来解决。把初始四围与其颜色相同的位置进行渲染,渲染了一个位置,就找其周围与其颜色相同的位置进行渲染。同时还需要判断四周的位置是否越界。如果渲染颜色和初始位置的颜色不同的话,我们渲染时候,仅仅需要判断是否为原始位置的颜色相同,渲染后的位置和未被渲染的位置能够清楚的区分,但是如果初始位置的颜色和渲染染色相同就会区分不了该位置是渲染过的,还是未被渲染的和初始位置原色相同的。为了解决这个问题,我们就引入一个标记数组 int[][] book 来标记该位置是否被渲染过了。

✨ 解题代码

    int[][] nextP= {{1,0},{-1,0},{0,-1},{0,1}};//偏移数组,通过原位置找到相邻的四个位置
    public int[][] floodFill(int[][] image, int sr, int sc, int color) {
        int oldColor = image[sr][sc];//记录要修改坐标的旧颜色
        int row = image.length;
        int col = image[0].length;
        int[][] book = new int[row][col];//创建一个标记数组
        DFS(image,book,sr,sc,oldColor,color,row,col);//深度优先搜索寻找是否有相同颜色的位置

        return image;
    }

    private void DFS(int[][] image, int[][] book, int sr, int sc, int oldColor, int color,int row,int col) {
        image[sr][sc] = color;//修改当前位置的颜色
        book[sr][sc] = 1;//标记当前位置已经被修改过了
        for (int i = 0; i < 4; i++) {//搜索上下左右四个位置的颜色是否符合原颜色
            int newX = sr + nextP[i][0];
            int newY = sc + nextP[i][1];
            if (newX < 0 || newX >= row
                || newY < 0 || newY >= col) {//判断新坐标是否越界
                continue;
            }
            //判断当前位置是否需要进行图像渲染
            if (image[newX][newY] == oldColor && book[newX][newY] == 0){
                //新的位置的处理
                DFS(image,book,newX,newY,oldColor,color,row,col);
            }
        }
    }

3.被围绕的区域

原题链接

✨问题描述:

给你一个 m x n 的矩阵 board ,由若干字符 ‘X’ 和 ‘O’ ,找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。

✨题目案例:

案例1: 输入:board =
[[“X”,“X”,“X”,“X”],[“X”,“O”,“O”,“X”],[“X”,“X”,“O”,“X”],[“X”,“O”,“X”,“X”]]
输出:[[“X”,“X”,“X”,“X”],[“X”,“X”,“X”,“X”],[“X”,“X”,“X”,“X”],[“X”,“O”,“X”,“X”]]
解释:被围绕的区间不会存在于边界上,换句话说,任何边界上的 ‘O’ 都不会被填充为 ‘X’。 任何不在边界上,或不与边界上的 ‘O’ 相连的
‘O’ 最终都会被填充为 ‘X’。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

案例2:
输入:board = [[“X”]]
输出:[[“X”]]

✨ 题目分析:

在这里插入图片描述
把整个区域扩大一下,变成上图这种。上图中红圈里的就是被包围的区域,被包围的区域比较不容易找到,但是未被包围的区域,就比较容易的找到了。我们可以用深度优先搜索的方式进行找到没有被包围的区域,间接找到被包围的区域。

✨ 解题代码

    int[][] nextP = {{1,0},{-1,0},{0,1},{0,-1}};//方向数组,下一步从哪个方向搜索 下 上 右 左

    public void solve(char[][] board) {
        int row = board.length;
        int col = board[0].length;
        //用逆向思维的方式求未被包围的区域,间接求出被包围的区域
        for (int i = 0; i < row; i++) {//寻找左列边界的区域中‘O’的位置
            if (board[i][0] == 'O'){
                DFS(board,i,0,row,col);
            }
            if (board[i][col - 1] == 'O'){//寻找右列边界的区域中‘O’的位置
                DFS(board,i,col - 1,row,col);
            }
        }
        for (int j = 0; j < col; j++) {
            if (board[0][j] == 'O'){//判断上边界是否有‘O’
                DFS(board,0,j,row,col);
            }
            if (board[row - 1][j] == 'O'){//判断下边界是否有‘O’
                DFS(board,row - 1,j,row,col);
            }
        }
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (board[i][j] == 'O'){
                    board[i][j] = 'X';
                }
                if (board[i][j] == '*'){
                    board[i][j] = 'O';
                }
            }
        }
    }

    private void DFS(char[][] board, int x, int y, int row, int col) {
        board[x][y] = '*';//代表该‘O’已经被搜索过了
        for (int i = 0; i < 4; i++) {
            int newX = x + nextP[i][0];
            int newY = y + nextP[i][1];
            if (newX < 0 || newX >= row
                ||newY < 0 || newY >= col){//判断探索位置是否越界
                continue;
            }
            if (board[newX][newY] == 'O'){//判断该位置是否需要进行探索
                DFS(board,newX,newY,row,col);
            }
        }
    }

4.岛屿数量

原题链接

✨ 题目描述:

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。

✨ 题目案例:

案例1:

输入:grid = [
[“1”,“1”,“1”,“1”,“0”],
[“1”,“1”,“0”,“1”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“0”,“0”,“0”]
]
输出:1

案例2:

输入:grid = [
[“1”,“1”,“0”,“0”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“1”,“0”,“0”],
[“0”,“0”,“0”,“1”,“1”]
]
输出:3

✨ 题目分析:

这个问题和第二题的思路有很多类似的地方。都是进行一个深度优先搜索,但是第二题给出了搜索的起始位置。这个题目搜索的起始位置我们可以对整个数组进行遍历。我们可以对搜索过的陆地位置进行标记,因为此问题我们仅仅只有‘0’和‘1’两种情况,我们可以对grid数组本身进行进行字符的改变来表示他是一个已经被搜索过的陆地了,这个字符我们可以换成一个不同于‘0’和‘1’的,比如‘*’;

✨ 解题代码:

   int[][] nextP = {{1,0},{-1,0},{0,1},{0,-1}};//方向数组,下一步从哪个方向搜索 下 上 右 左
    public int numIslands(char[][] grid) {
        int row = grid.length;
        int col = grid[0].length;
        int count = 0;
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (grid[i][j] == '1'){
                    DFS(grid,i,j,row,col);
                    count++;
                }
            }
        }
        return count;
    }

    private void DFS(char[][] grid,int posX, int poxY ,int row, int col) {
        grid[posX][poxY] = '*';//对已经搜索过的陆地进行标记,以防重复搜索造成死递归。
        for (int i = 0; i < 4; i++) {
            int newX = posX + nextP[i][0];
            int newY = poxY + nextP[i][1];
            if (newX < 0 || newX >= row
                    || newY < 0 || newY >= col) {//判断是否是越界了
                continue;
            }
            if (grid[newX][newY] == '1'){//是未被搜索的陆地,就进行下一步搜索
                DFS(grid, newX, newY, row, col);
            }
        }
    }

5. 电话号码的字母组合

原题链接

✨ 题目描述:

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
在这里插入图片描述

✨ 题目案例:

案例1:

输入:digits = “23”
输出:[“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]

案例2:

输入:digits = “”
输出:[]

案例3:

输入:digits = “2”
输出:[“a”,“b”,“c”]

✨ 题目分析:

结合案例可以看出,这个问题得到的字母组合和digits字符串的长度相同。当digits长度为0的时候,得到的结果是没有任何元素的一个集合。我们可以建立一个联系,用电话按键数字对应字符串在深度优先搜索的时候用于查找我们数字对应的字符串,我们一听到建立关系用于查找我们第一反应是建立hashMap,但是在java中的hashMap一下定义那么多关系,书写时比较麻烦的,我们可以用字符串数组来代替hashMap来实现建立这个关系,用数组的下标(数字)来对应数组内容(字符串)。
我们这个问题在运用深度优先搜索对于前几个题不同的是,不是每个位置放置的内容可以相互交换,而是每个位置的数字对应的字符串依次放在对应位置。
在这里插入图片描述

✨ 题目代码:

    public List<String> letterCombinations(String digits) {
        List<String> list = new ArrayList<>();
        String curStr = "";
        int len = digits.length();//所需获得字符串的长度
        DFS(digits,list,curStr,0,len);
        return list;
    }
    String[] strings = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    private void DFS(String digits, List<String> list, String curStr, int digitIdx,int len) {
        if (len == digitIdx){
            if (len != 0){
                list.add(curStr);
            }
            return;
        }
        //进行深度优先搜索,

        int num = Integer.parseInt(digits.charAt(digitIdx) + "");//获取当钱位置的数字字符
        for (char ch: strings[num].toCharArray()) {
            DFS(digits,list,curStr + ch,digitIdx + 1,len);
        }
    }

6.数字组合

原题链接

✨ 题目描述:

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。

✨ 题目案例:

案例1:

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。

案例2:

输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

案例3:

输入: candidates = [2], target = 1
输出: []

✨ 题目解析:

我们这个题目也是用DFS进行解决。我们对一个数字进行递归,直到这个组合的数字和大于等于目标数字的时候我们进行终止继续向下搜索,我们需要进行回溯到上一个步骤,试试其他的数字怎么样。
下面就是案例1的DFS过程:

在这里插入图片描述
这个问题为了避免出现一个组合重复出现的情况,我们可以在DSF的时候,循环遍历从该数字对应字符串的位置往后进行搜索。

✨ 解题代码:

DFS求解,需要注意的是:allRet.add(new ArrayList<>(curRet)); 其中两个对象的类型都是List,所以我们得转化为 ArrayList<>()这种具体类

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> allRet = new ArrayList<>(new ArrayList<>());
        List<Integer> curRet = new ArrayList<>();
        int curSum = 0;//搜索当前情况下的数字和
        int prev = 0;//当前你所需要的DFS时加和的下标
        DFS(candidates,target,allRet,curRet,curSum,prev);

        return allRet;
    }

    private void DFS(int[] candidates, int target, List<List<Integer>> allRet, List<Integer> curRet, int curSum, int prev) {
        if (curSum >= target){
            if (curSum == target){
                //保存当前的解集
                allRet.add(new ArrayList<>(curRet));
            }
            return;
        }
        
        //累加的起始位置为上一项的位置
        for (int i = prev; i < candidates.length; i++) {

            //累加当前项
            curRet.add(candidates[i]);
            DFS(candidates,target,allRet,curRet,curSum + candidates[i],i);
            //回溯
            curRet.remove(curRet.size() - 1);
        }

    }

7. 活字印刷

原题链接

✨ 题目描述:
你有一套活字字模 tiles,其中每个字模上都刻有一个字母 tiles[i]。返回你可以印出的非空字母序列的数目。
注意:本题中,每个活字字模只能使用一次。

✨ 题目案例:

案例1:

输入:“AAB”
输出:8
解释:可能的序列为 “A”, “B”, “AA”, “AB”, “BA”, “AAB”, “ABA”, “BAA”。

案例2:

输入:“AAABBC”
输出:188

案例3:

输入:“V”
输出:1

提示:

  • 1 <= tiles.length <= 7
  • tiles 由大写英文字母组成

✨ 题目分析:

该题目一样是用DFS来进行解题。但是改题目不一样的地方是每个活字字模只能使用一次,也就是每个位置的字符只能用一次,我们为了避免出现一个位置的字符进行多次出现,我们可以创建一个标记数组来标记是否该位置的字符已经在搜索过程中被使用到了。

✨ 解题代码:

    public int numTilePossibilities(String tiles) {
        Set<String> set = new HashSet<>();
        String curStr = "";
        int[] book = new int[tiles.length()];//标记字符串中的字符是否已经搜索过了。
        DFS(tiles,set,curStr,book);
        return set.size();
    }

    private void DFS(String tiles, Set<String> set, String curStr, int[] book) {
        if (curStr.length() != 0){
            set.add(curStr);
        }
        if (curStr.length() == tiles.length()){
            return;
        }
        for (int i = 0; i < tiles.length(); i++) {
            if (book[i] == 0){
                book[i] = 1;
                //进行深度优先搜索
                DFS(tiles,set,curStr + tiles.charAt(i),book);
                //进行回溯
                book[i] = 0;
            }
        }
    }

8. N皇后

✨ 题目描述:

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。

✨ 题目案例:

案例1:

在这里插入图片描述输入:n = 4输出:[[“.Q…”,“…Q”,“Q…”,“…Q.”],[“…Q.”,“Q…”,“…Q”,“.Q…”]]
解释:如上图所示,4 皇后问题存在两个不同的解法。

案例2:

输入:n = 1
输出:[[“Q”]]

✨ 题目分析:

我们就以案例1,来进行DFS分析如下图:

在这里插入图片描述
改图中展示 了找到其中一种n皇后的摆法,其他摆法也是按照这种思路进行DFS和回溯。
我们现在最主要的是如何进行判断该位置是否是违规的位置。我们从横纵方向+斜主对角线的坐标,进行了以下分析:

横:x坐标相同
纵:y坐标相同
正对角线:newX - newY = x - y(坐标差相同)
斜对角线:newX + newY == x + y(坐标和相同)

我们就可以针对已经摆放好的皇后来进行判断该位置是否违法,不违法就可以摆放新的皇后,摆放皇后的数量等于n就是一种摆放方式。

✨ 解题代码:

class pair{
    public int x;
    public int y;

    public pair(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
class Solution {
    public List<List<String>> solveNQueens(int n) {
        List<List<pair>> allRet = new ArrayList<>();
        List<pair> curRet = new ArrayList<>();
        DFS(allRet,curRet,0,n);
        //System.out.println(allRet.toString());
        return transResult(allRet,n);
    }
    void DFS(List<List<pair>> allRet,List<pair> curRet,int curRow,int n){
        //如果每一行都没有冲突,则是一种可行方案
        if (curRow == n){
            allRet.add(new ArrayList<>(curRet));
            return;
        }

        //确定当前行的每一个位置是否和已经确定的位置有冲突
        for (int i = 0; i < n; i++) {
            if(isValidPos(curRet,curRow,i)){
                curRet.add(new pair(curRow,i));//把当前位置存放到当前情况中
                //处理下一行
                DFS(allRet,curRet,curRow + 1,n);
                //回溯
                curRet.remove(curRet.size() - 1);//尾删
            }

        }
    }

    private boolean isValidPos(List<pair> curRet, int row, int col) {
        for (pair pos: curRet) {
            if (pos.y == col || pos.x + pos.y == row + col
                    || pos.x - pos.y == row - col){
                return false;
            }
        }
        return true;
    }
    private List<List<String>> transResult(List<List<pair>> allRet, int n) {
        List<List<String>> allMet = new ArrayList<>();
        for (List<pair> curRet : allRet) {
            List<String> curMat = new ArrayList<>();
            for (pair pos: curRet) {
                StringBuilder str = new StringBuilder();
                for (int i = 0; i < n; i++) {
                    str.append('.');
                }
                str.setCharAt(pos.y,'Q');
                curMat.add(str.toString());
            }
            allMet.add(curMat);
        }
        return allMet;
    }

}

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

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

相关文章

嵌入式和Python(二):python初识及其基本使用规则

目录 一&#xff0c;python基本特点 二&#xff0c;python使用说明 ● 两种编程方式 ① 交互式编程 ② 脚本式编程 ● python中文编码 ● python行和缩进 ● python引号 ● python空行 ● python等待用户输入 ① 没有转换变量类型 ② 转换变量类型 ● python变…

[Pytorch]DataSet和DataLoader逐句详解

将自己的数据集引入Pytorch是搭建属于自己的神经网络的重要一步&#xff0c;这里我设计了一个简单的实验&#xff0c;结合这个实验代码&#xff0c;我将逐句教会大家如何将数据引入DataLoader。 这里以目标检测为例&#xff0c;一个batch中包含图片文件、先验框的框体坐标、目标…

【C语言进阶:指针的进阶】你真分得清sizeof和strlen?

本章重点内容&#xff1a; 字符指针指针数组数组指针数组传参和指针传参函数指针函数指针数组指向函数指针数组的指针回调函数指针和数组面试题的解析这篇博客 FLASH 将带大家一起来练习一些容易让人凌乱的题目&#xff0c;通过这些题目来进一步加深和巩固对数组&#xff0c;指…

基于注解@Transactional事务基本用法

关于概念性的放在最下面,熟读几遍 在使用时候也没多关注,总是加个Transactional 初识下 一般查询 Transactional(propagation Propagation.SUPPORTS) 增删改 Transactional(propagation Propagation.REQUIRED) 当然不能这么马虎 Spring中关于事务的传播 一个个测试,事…

计算机网络第八版——第一章课后题答案(超详细)

第一章 该答案为博主在网络上整理&#xff0c;排版不易&#xff0c;希望大家多多点赞支持。后续将会持续更新&#xff08;可以给博主点个关注~ 【1-01】计算机网络可以向用户提供哪些服务&#xff1f; 解答&#xff1a;这道题没有现成的标准答案&#xff0c;因为可以从不同的…

操作系统——15.FCFS、SJF、HRRN调度算法

这节我们来看一下进程调度的FCFS、SJF、HRRN调度算法 目录 1.概述 2.先来先服务算法&#xff08;FCFS&#xff0c;First Come First Serve&#xff09; 3.短作业优先算法&#xff08;SJF&#xff0c;Shortest Job First&#xff09; 4.高响应比优先算法&#xff08;HRRN&…

Jackson CVE-2018-5968 反序列化漏洞

0x00 前言 同CVE-2017-15095一样&#xff0c;是CVE-2017-7525黑名单绕过的漏洞&#xff0c;主要还是看一下绕过的调用链利用方式。 可以先看&#xff1a; Jackson 反序列化漏洞原理 或者直接看总结也可以&#xff1a; Jackson总结 影响版本&#xff1a;至2.8.11和2.9.x至…

【数据结构】AVL平衡二叉树底层原理以及二叉树的演进之多叉树

1.AVL平衡二叉树底层原理 背景 二叉查找树左右子树极度不平衡&#xff0c;退化成为链表时候&#xff0c;相当于全表扫描&#xff0c;时间复杂度就变为了O(n) 插入速度没影响&#xff0c;但是查询速度变慢&#xff0c;比单链表都慢&#xff0c;每次都要判断左右子树是否为空 需…

java Spring JdbcTemplate配合mysql实现数据批量修改

其实这个操作和批量添加挺像的 调的同一个方法 首先 我们看数据库结构 这是我本地的 mysql 里面有一个test数据库 里面有一张user_list表 然后创建一个java项目 然后 引入对应的JAR包 在src下创建 dao 目录 在下面创建一个接口 叫 BookDao 参考代码如下 package dao;impo…

进程控制~

进程控制 &#xff08;创建、终止&#xff0c;等待&#xff0c;程序替换&#xff09; 进程创建&#xff1a; pid_t fork();父子进程&#xff0c;数据独有&#xff0c;代码共享&#xff0c;各有各的地址 pit_t vfork();父进程阻塞&#xff0c;直到子进程exit退出或者程序替换之…

电力系统稳定性的定义与分类

1电力系统稳定性的定义与分类 IEEE给出电力系统稳定性定义&#xff1a;电力系统稳定性是指电力系统这样的一种能力—对于给定的初始运行状态&#xff0c;经历物理扰动后&#xff0c;系统能够重新获得运行平衡点的状态&#xff0c;同时绝大多数系统变量有界&#xff0c;因此整个…

自己写一个简单的IOC

什么是SpringIOC&#xff1f; 答&#xff1a;IOC即控制反转&#xff0c;就是我们不在手动的去new一个对象&#xff0c;而是将创建对象的权力交给Spring去管理&#xff0c;我们想要一个User类型的对象&#xff0c;就只需要定义一个User类型的变量user1&#xff0c;然后让Spring去…

蓝桥杯-刷题统计

蓝桥杯-刷题统计1、问题描述2、解题思路3、代码实现3.1 方案一&#xff1a;累加方法(超时)3.2 方案二1、问题描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a 道题目, 周六和周日每天做 b 道题目。请你帮小明计算, 按照计划他将在 第几天实现做题数…

KNN学习报告

原理 KNN算法就是在其表征空间中&#xff0c;求K个最邻近的点。根据已知的这几个点对其进行分类。如果其特征参数只有一个&#xff0c;那么就是一维空间。如果其特征参数只有两个&#xff0c;那么就是二维空间。如果其特征参数只有三个&#xff0c;那么就是三维空间。如果其特征…

软件设计师教程(七)计算机系统知识-操作系统知识

软件设计师教程 软件设计师教程&#xff08;一&#xff09;计算机系统知识-计算机系统基础知识 软件设计师教程&#xff08;二&#xff09;计算机系统知识-计算机体系结构 软件设计师教程&#xff08;三&#xff09;计算机系统知识-计算机体系结构 软件设计师教程&#xff08;…

Redis十大类型——Hash常见操作

Redis十大类型——Hash常见操作命令操作简列存放及获取获取健值对长度元素查找列出健值对对数字进行操作赋值hsetnx很明显咯它也是以健值对方式存在的&#xff0c;只不过value也就是值&#xff0c;在这里也变成了一组简直对。 &#x1f34a;个&#x1f330;&#xff1a; 想必多…

【Linux】P3 用户与用户组

用户与用户组root 超级管理员设置超级管理员密码切换到超级管理员sudo 临时使用超级权限用户与用户组用户组管理用户管理getentroot 超级管理员 设置超级管理员密码 登陆后不会自动开启 root 访问权限&#xff0c;需要首先执行如下步骤设定 root 超级管理员密码 1、解除 roo…

【C++】string的使用及其模拟实现

文章目录1. STL的介绍1.1 STL的六大组件1.2 STL的版本1.3 STL的缺陷2. string的使用2.1 为什么要学习string类&#xff1f;2.2 常见构造2.3 Iterator迭代器2.4 Capacity2.5 Modifiers2.6 String operations3. string的模拟实现3.1 构造函数3.2 拷贝构造函数3.3 赋值运算符重载和…

DevOps实战50讲-(2)Jenkins配置

1. Docker镜像方式安装拉取Jenkins镜像docker pull jenkins/jenkins编写docker-compose.ymlversion: "3.1" services:jenkins:image: jenkins/jenkinscontainer_name: jenkinsports:- 8080:8080- 50000:50000volumes:- ./data/:/var/jenkins_home/首次启动会因为数据…

iis之web服务器搭建、部署(详细)~千锋

目录 Web服务器 部署web服务器 实验一 发布一个静态网站 实验二 一台服务器同时发布多个web站点 网站类型 Web服务器 也叫网页服务或HTTP服务器web服务器使用的协议是HTTPHTTP协议端口号&#xff1a;TCP 80、HTTPS协议端口号&#xff1a;TCP 443Web服务器发布软件&…