C++算法学习心得六.回溯算法(3)

news2024/11/15 15:55:43

1.子集II(90题)

题目描述:

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

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

示例:

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

回溯法:集合里有重复元素了,而且求取的子集要去重,注意去重需要先对集合排序,同一树层上重复取2 就要过滤掉,同一树枝上就可以重复取2,因为同一树枝上元素的集合才是唯一子集,这里我们需要收集所有子集,所以需要刚进入递归收集节点

class Solution {
private:
    vector<int> path;
    vector<vector<int>> result;
    //使用数组进行去重逻辑
    void backtracking(vector<int>& nums, int startindex, vector<bool>& used) {
        result.push_back(path);
        for (int i = startindex; i < nums.size(); i++) {
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
                continue;//去重条件,设置这个也是在树层去重
            }
            path.push_back(nums[i]);
            used[i] = true;
            backtracking(nums, i + 1, used);
            path.pop_back();
            used[i] = false;
        }
    }

public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<bool>used(nums.size(),false);
        sort(nums.begin(),nums.end());//去重的话需要先对数组进行排序
        backtracking(nums,0,used);
        return result;
    }
};
  • 时间复杂度: O(n * 2^n)
  • 空间复杂度: O(n)

2.递增子序列(491题) 

题目描述:

给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是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]]

回溯法:本题求自增子序列,是不能对原数组进行排序的,排完序的数组都是自增子序列了。同一父节点下的同层上使用过的元素就不能再使用了,哈希表是记录本层元素是否重复使用,新的一层uset都会重新定义(清空),所以要知道uset只负责本层

class Solution { 
private:
    vector<int>path;
    vector<vector<int>>result;
    void backtracking(vector<int>& nums,int startindex){
        if(path.size() > 1)result.push_back(path);//因为本题要求是需要大于两个元素的子集
        unordered_set<int>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 result;
    }
};
  • 时间复杂度: O(n * 2^n)
  • 空间复杂度: O(n)

 3.全排列(46题)

题目描述:

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

示例:

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

回溯: 首先排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方,排列问题需要一个used数组,标记已经选择的元素,收集元素的数组path的大小达到和nums数组一样大的时候,说明找到了一个全排列,也表示到达了叶子节点。而used数组,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次。

class Solution {
private:
    vector<int>path;
    vector<vector<int>>result;
    //排列需要传入参数有判断是否使用的数组
    void backtracking(vector<int>& nums,vector<bool>& used){
        if(path.size() == nums.size()){
            result.push_back(path);//终止条件,我们收集叶子节点,判断路径大小是否符合数组大小
            return;
        }
        //i从0开始记录,排列不用和组合一样设置startindex,
        for(int i = 0;i < nums.size();i++){
            if(used[i] == true)continue;//判断是否使用过
            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) {
        path.clear();
        result.clear();
        vector<bool>used(nums.size(),false);//记得定义一个判断是否使用过的数组
        backtracking(nums,used);//回溯
        return result;
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)
  • 每层都是从0开始搜索而不是startIndex
  • 需要used数组记录path里都放了哪些元素了

 4.全排列 II(47题)

题目描述:

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

示例 1:

  • 输入:nums = [1,1,2]
  • 输出: [[1,1,2], [1,2,1], [2,1,1]]

回溯法: 需要去重逻辑,强调的是去重一定要对元素进行排序,这样我们才方便通过相邻的节点来判断是否重复使用了,对同一树层,前一位(也就是nums[i-1])如果使用过,那么就进行去重。组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果

class Solution {
private:
    vector<int> path;
    vector<vector<int>> result;
    //回溯函数,这里需要一个数组定义使用过的数
    void backtracking(vector<int>& nums, vector<bool>& used) {
        if (path.size() == nums.size()) {
            result.push_back(path);//如果路径大小等于数组大小则收集结果
            return;
        }
        //注意排列问题需要从0开始遍历树层
        for (int i = 0; i < nums.size(); i++) {
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
                continue;//这里使用组合的树层去重的逻辑
            }
            //首先判断是否使用过,在进行递归回溯
            if (used[i] == false) {
                used[i] = true;//遍历过的元素定义为使用过
                path.push_back(nums[i]);//路径加入该元素
                backtracking(nums, used);//递归
                used[i] = false;//回溯
                path.pop_back();//回溯
            }
        }
    }

public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(),nums.end());//使用数组时候我们需要对其进行排序
        vector<bool>used(nums.size(),false);//定义一个全是false的数组
        backtracking(nums,used);//
        return result;
    }
};
  • 时间复杂度: O(n! * n)
  • 空间复杂度: O(n)

 5.重新安排行程(332题)

题目描述:

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

提示:

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

示例 1:

  • 输入:[["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]]
  • 输出:["JFK", "MUC", "LHR", "SFO", "SJC"]

 回溯:

一个行程中,如果航班处理不好容易变成一个圈,成为死循环,在解题的过程中没有对集合元素处理好,就会死循环。

记录映射关系一个机场映射多个机场,机场之间要靠字母序排列,一个机场映射多个机场,可以使用std::unordered_map,如果让多个机场之间再有顺序的话,就是用std::map 或者std::multimap 或者 std::multiset。unordered_map<string, map<string, int>> targets:unordered_map<出发机场, map<到达机场, 航班次数>> targets。出发机场和到达机场是会重复的,搜索的过程没及时删除目的机场就会死循环。

搜索的过程中就是要不断的删multiset里的元素,那么推荐使用unordered_map<string, map<string, int>> targets在遍历 unordered_map<出发机场, map<到达机场, 航班次数>> targets的过程中,可以使用"航班次数"这个字段的数字做相应的增减,来标记到达机场是否使用过了。如果“航班次数”大于零,说明目的地还可以飞,如果“航班次数”等于零说明目的地不能飞了,而不用对集合做删除元素或者增加元素的操作

 注意返回值需要用bool类型,只需要找到一个行程,就是在树形结构中唯一的一条通向叶子节点的路线,找到了这个叶子节点了直接返回,可以说本题既要找到一个对数据进行排序的容器,而且还要容易增删元素,迭代器还不能失效

class Solution {
private:
     unordered_map<出发机场, map<到达机场, 航班次数>> targets
    unordered_map<string, map<string, int>> targets;
    bool backtracking(int ticketNum, vector<string>& result) {
        if (result.size() == ticketNum + 1) {
            return true;
        }
        for (pair<const string, int>& target :
             targets[result[result.size() - 1]]) {
             记录到达机场是否飞过了
            if (target.second > 0) {
                result.push_back(target.first);
                target.second--;
                if (backtracking(ticketNum, result))
                    return true;
                result.pop_back();
                target.second++;
            }
        }
        return false;
    }

public:
    vector<string> findItinerary(vector<vector<string>>& tickets) {
        vector<string> result;
        for (const vector<string>& vec : tickets) {
            targets[vec[0]][vec[1]]++; // 记录映射关系
        }
        result.push_back("JFK"); // 起始机场
        backtracking(tickets.size(), result);
        return result;
    }
};

一定要加上引用即 & target,因为后面有对 target.second 做减减操作,如果没有引用,单纯复制,这个结果就没记录下来,那最后的结果就不对了。

加上引用之后,就必须在 string 前面加上 const,因为map中的key 是不可修改了

6.N皇后(51题)

题目描述:

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

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

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

回溯法:皇后们的约束条件:

  1. 不能同行
  2. 不能同列
  3. 不能同斜线

 二维矩阵中矩阵的高就是这棵树的高度,矩阵的宽就是树形结构中每一个节点的宽度。

只要搜索到了树的叶子节点,说明就找到了皇后们的合理位置了。

class Solution {
private:
vector<vector<string>> result;
// n 为输入的棋盘大小
// row 是当前递归到棋盘的第几行了
void backtracking(int n, int row, vector<string>& chessboard) {
    if (row == n) {
        result.push_back(chessboard);
        return;
    }
    for (int col = 0; col < n; col++) {
        if (isValid(row, col, chessboard, n)) { // 验证合法就可以放
            chessboard[row][col] = 'Q'; // 放置皇后
            backtracking(n, row + 1, chessboard);
            chessboard[row][col] = '.'; // 回溯,撤销皇后
        }
    }
}
bool isValid(int row, int col, vector<string>& chessboard, int n) {
    // 检查列
    for (int i = 0; i < row; i++) { // 这是一个剪枝
        if (chessboard[i][col] == 'Q') {
            return false;
        }
    }
    // 检查 45度角是否有皇后
    for (int i = row - 1, j = col - 1; i >=0 && j >= 0; i--, j--) {
        if (chessboard[i][j] == 'Q') {
            return false;
        }
    }
    // 检查 135度角是否有皇后
    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) {
        result.clear();
        std::vector<std::string> chessboard(n, std::string(n, '.'));
        backtracking(n, 0, chessboard);
        return result;
    }
};

棋盘的宽度就是for循环的长度,递归的深度就是棋盘的高度,这样就可以套进回溯法的模板里了. 

7. 解数独(37题)

题目描述:

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

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

棋盘搜索问题可以使用回溯法暴力搜索,只不过这次我们要做的是二维递归

因为解数独找到一个符合的条件(就在树的叶子节点上)立刻就返回,相当于找从根节点到叶子节点一条唯一路径,所以需要使用bool返回值。

一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,一行一列确定下来之后,递归遍历这个位置放9个数字的可能性!

class Solution {
private:
bool backtracking(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++) {     // (i, j) 这个位置放k是否合适
                    if (isValid(i, j, k, board)) {
                        board[i][j] = k;                // 放置k
                        if (backtracking(board)) return true; // 如果找到合适一组立刻返回
                        board[i][j] = '.';              // 回溯,撤销k
                    }
                }
                return false;  // 9个数都试完了,都不行,那么就返回false
            }
        }
    }
    return true; // 遍历完没有返回false,说明找到了合适棋盘位置了
}
bool isValid(int row, int col, char val, vector<vector<char>>& board) {
    for (int i = 0; i < 9; i++) { // 判断行里是否重复
        if (board[row][i] == val) {
            return false;
        }
    }
    for (int j = 0; j < 9; j++) { // 判断列里是否重复
        if (board[j][col] == val) {
            return false;
        }
    }
    int startRow = (row / 3) * 3;
    int startCol = (col / 3) * 3;
    for (int i = startRow; i < startRow + 3; i++) { // 判断9方格里是否重复
        for (int j = startCol; j < startCol + 3; j++) {
            if (board[i][j] == val ) {
                return false;
            }
        }
    }
    return true;
}
public:
    void solveSudoku(vector<vector<char>>& board) {
        backtracking(board);
    }
};

总结:

子集II:注意该题有重复元素,所以需要考虑树层去重,且需要子集所以需要收集所有树的结点,且也是组合问题,需要startindex取找位置,不要忘记加+1操作,结果收集语句的位置,使用used数组来去重的话需要对原来数组进行排序,不要忘记把used数组也要进行回溯,

递增子序列:此题和去重题目很像,但是 注意不能直接用原来套路去实现,uesd数组需要去排序,但是题目序列顺序不能颠倒,所以采用哈希表的形式来实现,使用set,因为还是取子集,stratindex注意,i+1取仍然树层去重,这里需要循环条件或者是进入下一次递归的条件,因为是递增的,所以注意要取数组最后元素和当前元素对比,然后不能空数组操作,哈希表要去实现去重,find函数到end,没找到说明没重复,这里回溯也需要注意,不必对哈希表清空操作。

全排列:无重复序列的排列,排列数组有顺序,使用Used数组来标记是否使用过该数字,该题也是需要在叶子节点收集结果,used数组来记录我们那些元素使用过,我们使用uesd == false来进行递归回溯,排列和组合 不同在于组合需要startindex,排列从0开始,注意我们需要对使用过的数组来进行used变化和回溯,

全排列II:是需要有重复元素,需要进行树层去重操作,这里仍然需要used数组来进行去重操作,子集问题是收集所有树节点,排列和组合问题是回收所有的叶子节点,排列需要从0去遍历,组合从startindex来遍历,这里的循环逻辑是used[i]==false就进行递归循环操作,这里有一个细节需要注意,used数组需要进行回溯,依然需要进行排序来,

重新安排行程:我们需要记录好映射关系,找到对应的路径不要陷入死循环,这里数据格式的选择很重要,选择哈希表来去重,也要注意是有返回值,找到了一条路径就立即返回,要注意数据处理方式也需要注意

N皇后:回溯法来实现,二维矩阵中矩阵的高就是这棵树的高度,矩阵的宽就是树形结构中每一个节点的宽度,这里我们需要收集树的叶子节点,就是我们需要的结果,需要写判断合法函数,如果合法就进行递归和回溯操作,最后满足条件收集结果

解数独:二维递归,一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,一行一列确定下来之后,递归遍历这个位置放9个数字的可能性,其实和n皇后很像,就是也需要处理逻辑,而且只是再维度上扩大了而已

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

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

相关文章

centos 安装mysql5.7教程

一&#xff0c;配置yum mysql5.7安装源 配置yum mysql5.7安装源 yum localinstall https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm 配置mysql5.7安装源成功 查看配置成功的安装源 yum repolist enabled | grep "mysql*" 执行后看到已配…

大模型|基础——长短时记忆网络

文章目录 LSTM遗忘门输入门整合信息特点实现神经单元的内部计算门控控制——可以动态选择信息在大数据量的情况下&#xff0c;可有效缓解梯度 LSTM 遗忘门 遗忘门&#xff0c;是否进行遗忘。 如果通过计算&#xff0c;计算出来的结果为0&#xff0c;就选择遗弃。 如果遗忘&…

14.4.2 Flash读取与修改数据库中的数据

14.4.2 Flash读取与修改数据库中的数据 计数器是网站必不可少的统计工具&#xff0c;使用计数器可以使网站管理者对网站的访问情况有一个清晰的了解。如果仅仅是统计首页访问量的话&#xff0c;用文本文件来存储数据就可以了&#xff0c;但如果统计的数据量比较大的话(如文章系…

MySQL和Redis的事务有什么异同?

MySQL和Redis是两种不同类型的数据库管理系统&#xff0c;它们在事务处理方面有一些重要的异同点。 MySQL事务&#xff1a; ACID属性&#xff1a; MySQL是一个关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;支持ACID属性&#xff0c;即原子性&#xff08;Ato…

【CANoe使用大全】——Graphics窗口

文章目录 1.Graphics作用2.Graphics窗口打开方式2.1.Analysis—>Graphics2.2.Measurement Setup ------> Graphics 3.变量添加4.Graphics窗口菜单栏介绍4.1. 单个测量光标4.2. 差分测量光标4.3.Y轴的显示方式4.3.1.Show Y-Axis of Selected Signal4.3.2.Show All Y-Axis4…

【java题解】题目 1779: 你的第一个程序;题目 1779: 你的第一个程序;题目 1173: 计算球体积

目录 题目 1779: 你的第一个程序 题目描述 输入格式 输出格式 样例输入 样例输出 题解 题目 1173: 计算球体积 题目描述 输入格式 输出格式 样例输入 样例输出 题解 题目 1267: AB Problem 题目描述 输入格式 输出格式 样例输入 样例输出 题解 从今天开始…

前端面试题-深拷贝浅拷贝-浏览器存储-原型链-闭包-call,bind,apply的区别

前端面试题-深拷贝浅拷贝-浏览器存储-原型链-闭包-call,bind,apply的区别 什么是深拷贝什么是浅拷贝cookie,sessionStorage和localStrorage的区别是什么什么是原型链prototype原型 作用域什么是闭包&#xff0c;闭包的作用场景是什么call bind和apply的区别 什么是深拷贝什么是…

Android颜色选择器

Android颜色选择器&#xff0c;弹框提示选择颜色。效果如图。点击或者滑动圆环和底部横向渐变色调整颜色&#xff0c;中间圆圈的颜色就是最终选中的颜色。点击圆圈确认颜色。 使用 //颜色选择Dialogprivate void showColorPickDialog(int position, int colorInt){ColorPickerD…

Tomcat session复制及session共享技术

目录 1、环境 2、配置测试页面 3、配置session共享 前言&#xff1a; 为什么要做session复制或共享 实现Session复制或Session共享的目的是为了在多个Tomcat实例之间实现Session的无缝转移和共享&#xff0c;以提供更高的可伸缩性、负载均衡和容错性。以下是一些原因&#x…

浅谈DNS的工作原理及其作用

DNS&#xff0c;全称为Domain Name System&#xff0c;即域名系统&#xff0c;是一种用于将域名和IP地址相互映射的分布式数据库系统。它将可读的域名转换为对应的IP地址&#xff0c;使得用户可以更方便地通过域名来访问网络上的资源。今天锐成就简单探讨一下DNS的工作原理及其…

Redis 面试题 | 11.精选Redis高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Java服务端使用freemarker+wkhtmltoimage生成Echart图片

目录 1.通过 freemarker 将ftl转成html 1.1 freemarker 手册: 1.2 添加freemarker maven依赖 1.3 添加 echart-test.ftl 模版文件 1.4 添加 FreemarkerTool 工具类 1.5 添加测试main方法 1.6 运行,生成echart-test-时间戳.html 文件 2. 通过wkhtmltoimage将html 转为p…

Flink max maxby区别

max只会显示指定字段的大小变化&#xff0c;而maxBy会显示其他字段的变化。 max&#xff1a;取指定字段的当前的最大值&#xff0c;如果有多个字段&#xff0c;其他非比较字段&#xff0c;以第一条为准。 maxBy&#xff1a;取指定字段的当前的最大值&#xff0c;如果有多个字段…

企业出海数据合规:GDPR下数据出境的条件

一、GDPR对数据出镜的规制 GDPR第五章集中规定了数据跨境流动的形式&#xff0c;总的来说给出了三种个人数据出境的条件&#xff0c;分别是基于充分决定的数据传输&#xff1b;基于采取适当保障措施的数据传输&#xff1b;以及基于特殊情况的减损条款&#xff0c;分别对应的是…

windows下git pull超时,ping不通github

报错 ssh: connect to host github.com port 22: Connection timed out fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. 解决办法 修改hosts 最后加一行&#xff0c;文件位置&#xff1a;…

Leetcode:二分搜索树层次遍历

题目&#xff1a; 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例&#xff1a; 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9,…

16、Kafka ------ SpringBoot 整合 Kafka (配置 Kafka 属性 及对应的 属性处理类 解析)

目录 配置 Kafka 及对应的 属性处理类配置KafkaKafka配置属性的约定代码演示生产者相关的配置消费者相关的配置 代码&#xff08;配置文件&#xff09;application.properties 配置 Kafka 及对应的 属性处理类 配置Kafka spring.kafka.* 开头的配置属性&#xff0c;这些属性将由…

MSB20M-ASEMI小功率家电专用MSB20M

编辑&#xff1a;ll MSB20M-ASEMI小功率家电专用MSB20M 型号&#xff1a;MSB20M 品牌&#xff1a;ASEMI 封装&#xff1a;UMSB-4 最大重复峰值反向电压&#xff1a;1000V 最大正向平均整流电流(Vdss)&#xff1a;2A 功率(Pd)&#xff1a;50W 芯片个数&#xff1a;4 引…

OpenHarmony开发——GN快速上手

背景 最近在研究鸿蒙操作系统的开源项目OpenHarmony&#xff0c;该项目使用了GNNinja工具链进行配置&#xff0c;编译&#xff0c;于是开始研究GN如何使用。 本文的所有信息均来自GN官网和本人个人体会。 GN快速入门 使用GN GN的主要功能是根据配置文件&#xff08;.gn, BU…

【排序2】-交换排序

&#x1f47b;交换排序 &#x1f384;1、基本思想及特点&#x1f384;2、冒泡排序&#x1f384;3、快速排序&#xff08;挖坑法&#xff09;&#x1f384;4、快速排序优化&#x1f38a;4.1 三数取中法选key&#x1f38a;4.2 递归到小的子区间时&#xff0c;可以考虑使用插入排序…