代码随想录算法训练营刷题复习8 :回溯算法——子集、排列、棋盘问题

回溯算法

子集问题

①res,path; backtracking函数

②无递归终止条件判断,直接path存入res;

③递归需要startIndex;

④(补充)"有重复元素、不能包含重复的解集" 在for循环多加判断条件:i>0 && used[i-1]==false && nums[i]==nums[i-1] 跳过同层重复元素的处理

  1. 78. 子集
    递归终止条件可以省略(与for循环的判断条件一致),每次递归调用的时候先把结果写入到res中
  2. 90. 子集 II
    此题关于"有重复元素、不能包含重复的解集"的处理方法与组合问题中的一致。其他没有什么强调的了。

78. 子集

递归终止条件可以省略(与for循环的判断条件一致),每次递归调用的时候先把结果写入到res中

cpp 复制代码
class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;

    void backtracking(vector<int>& nums, int startIndex) {
        res.push_back(path);

        for(int i=startIndex;i<nums.size();i++) {
            path.push_back(nums[i]);
            backtracking(nums,i+1);
            path.pop_back();
        }

    }

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

90. 子集 II

此题关于"有重复元素、不能包含重复的解集"的处理方法与组合问题中的一致。

cpp 复制代码
class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    void backtracking(vector<int>& nums,int startIndex, vector<bool>& used) {
        res.push_back(path);

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

排列问题

全排列需要对所有元素进行排列,

①终止条件:path.size == nums.size()

②for遍历元素集合为所有元素,用used控制不重复

③有重复元素,要求解集不重复的处理条件:i>0 && nums[i]==nums[i-1] && used[i-1]==false

  1. 46. 全排列
    排列问题,path写入res中一定是包含了nums的所有元素,只是排列顺序不同
    遍历的元素集合为所有元素,只是需要used数组,标记已使用过的元素避免出现重复
  2. 47. 全排列 II
    还是强调对于不重复解集的处理

46. 全排列

排列问题,path写入res中一定是包含了nums的所有元素,只是排列顺序不同

遍历的元素集合为所有元素,只是需要used数组,标记已使用过的元素避免出现重复

cpp 复制代码
class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;

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

        for(int i=0;i<nums.size();i++) {
            if(used[i]==true)
                continue;
            path.push_back(nums[i]);
            used[i]=true;
            backtracking(nums,used);
            path.pop_back();
            used[i]=false;
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<bool> used(nums.size(),false);
        backtracking(nums,used);
        return res;
    }
};

47. 全排列 II

还是强调对于不重复解集的处理

cpp 复制代码
class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;

    void backtracking(vector<int>& nums, vector<bool>& used) {
        if(path.size()==nums.size()) {
            res.push_back(path);
        }
        for(int i=0;i<nums.size();i++) {
            if(used[i]==true) {
                continue;
            }else if(i>0 && nums[i]==nums[i-1] && used[i-1]==false){
                continue;
            }
            path.push_back(nums[i]);
            used[i]=true;
            backtracking(nums,used);
            path.pop_back();
            used[i]=false;
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<bool> used(nums.size(),false);
        backtracking(nums,used);
        return res;
    }
};

棋盘问题

需要定义棋盘(或题目给出),一层or两层循环(看题目逻辑),单独的isValid函数判断放置是否合理

①backtracking函数,棋盘选择按行递归或者逐元素递归

②isValid函数判断放置是否合理

  1. 51. N 皇后
    1.构建棋盘 vector chessboard(n,string(n,'.'));
    2.逐行使用回溯,使用isValid函数判断放置位置是否合理
    3.isValid函数,判断列、45度方向、135度方向放置是否合理
  2. 37. 解数独
    1.双层循环,i j定位到要放数字的点,isValid判断是否符合逻辑,使用回溯递归调用
    2.isValid判断行、列,以及内部小九格是否有重复数字

51. N 皇后

1.构建棋盘 vector chessboard(n,string(n,'.'));

2.逐行使用回溯,使用isValid函数判断放置位置是否合理

3.isValid函数,判断列、45度方向、135度方向放置是否合理

cpp 复制代码
class Solution {
public:
    vector<vector<string>> res;
    void backtracking(int n,int row,vector<string>& chessboard) {
        if(row == n) {
            res.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;
            }
        }
        for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--) {
            if(chessboard[i][j]=='Q') {
                return false;
            }
        }
        for(int i=row-1,j=col+1;i>=0&&j<n;i--,j++) {
            if(chessboard[i][j]=='Q') {
                return false;
            }
        }
        return true;
    }
    vector<vector<string>> solveNQueens(int n) {
        vector<string> chessboard(n,string(n,'.'));
        backtracking(n,0,chessboard);
        return res;
    }
};

37. 解数独

1.双层循环,i j定位到要放数字的点,isValid判断是否符合逻辑,使用回溯递归调用

2.isValid判断行、列,以及内部小九格是否有重复数字

cpp 复制代码
class Solution {
public:
    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 c = '1';c<='9';c++) {
                        if(isValid(i,j,c,board)) {
                            board[i][j]=c;
                            if(backtracking(board)) {
                                return true;
                            }board[i][j]='.';
                        }
                            
                    }
                    return false;
                }
            }
        }
        return true;
    }

    bool isValid(int row,int col,char k,vector<vector<char>>& board) {
        for(int i=0;i<9;i++) {
            if(board[row][i] == k)
                return false;
        }
        for(int i=0;i<9;i++) {
            if(board[i][col] == k)
                return false;
        }
        
        int row_1 = (row/3)*3;
        int col_1 = (col/3)*3;
        for(int i=row_1;i<row_1+3;i++) {
            for(int j=col_1;j<col_1+3;j++) {
                if(board[i][j]==k)
                    return false;
            }
        }
        return true;
    }
    void solveSudoku(vector<vector<char>>& board) {
        backtracking(board);
    }
};
相关推荐
王老师青少年编程7 分钟前
gesp(二级)(12)洛谷:B3955:[GESP202403 二级] 小杨的日字矩阵
c++·算法·矩阵·gesp·csp·信奥赛
Kenneth風车42 分钟前
【机器学习(九)】分类和回归任务-多层感知机(Multilayer Perceptron,MLP)算法-Sentosa_DSML社区版 (1)111
算法·机器学习·分类
eternal__day1 小时前
数据结构(哈希表(中)纯概念版)
java·数据结构·算法·哈希算法·推荐算法
APP 肖提莫1 小时前
MyBatis-Plus分页拦截器,源码的重构(重构total总数的计算逻辑)
java·前端·算法
OTWOL1 小时前
两道数组有关的OJ练习题
c语言·开发语言·数据结构·c++·算法
QQ同步助手1 小时前
C++ 指针进阶:动态内存与复杂应用
开发语言·c++
qq_433554542 小时前
C++ 面向对象编程:递增重载
开发语言·c++·算法
易码智能2 小时前
【EtherCATBasics】- KRTS C++示例精讲(2)
开发语言·c++·kithara·windows 实时套件·krts
ཌ斌赋ད2 小时前
FFTW基本概念与安装使用
c++
带多刺的玫瑰2 小时前
Leecode刷题C语言之切蛋糕的最小总开销①
java·数据结构·算法