算法经典面试题(6)——回溯法

*题目编号为Leetcode中对应的题号。
某位大佬的Leetcode题解参考链接

回溯法

  1. (17 电话号码的字母组合) 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

示例:
输入:"23" 输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

    class Solution {
    
    
    private:
        vector<string> res;
        const string letterMap[10]={
    
    
        " ",// 0
        "",// 1
        "abc",// 2
        "def",// 3
        "ghi",// 4
        "jkl",// 5
        "mno",// 6
        "pqrs",// 7
        "tuv",// 8
        "wxyz"// 9
    }
        
    // s存放的是digits[0,index-1]中的数字组成的字母字符串
    // 寻找和digits[index]匹配的字母,获得digits[0,index-1]的字母字符串
    void findCombination(congst string &digits, int index, const string &s){
    
    
        if(index==digits.size()){
    
    
            res.push_back(s);// 这里不用清空s
            return;
        }
            
        char c=digits[index];
        string letters=letterMap['c'-'0'];
        for(int i=0;i<letters.size();i++)
            findCombination(digits, index+1, s+letters[i]);
    	
        return;
    public:
        
    vector<string> letterCombinations(string digits) {
    
    
        res.clear();
        if(digits=="")
            return res;
        
        findCombination(digits, 0, "")
        return res;
    }
    };
  1. (93复原IP地址) 给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。

    有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.'分隔。例如:“0.1.2.201” 和 “192.168.1.1” 是 有效的 IP 地址,但是 “0.011.255.245”、“192.168.1.312” 和 “[email protected]” 是 无效的 IP 地址。

    示例:

    输入:s = "25525511135"
    输出:["255.255.11.135","255.255.111.35"]
    输入:s = "101023"
    输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
    
class Solution {
    
    
public:
    vector<string> restoreIpAddresses(string s) {
    
    

        vector<string> res;
        vector<int> ip;
        dfs(s, 0, ip, res);
        return res;
    }

private:
    void dfs(const string& s, int index, vector<int>& ip, vector<string>& res){
    
    

        if(index == s.size()){
    
    
            if(ip.size() == 4)
                res.push_back(get_string(ip));
            return;
        }

        if(index == 0){
    
    
            ip.push_back(s[0] - '0');
            dfs(s, index + 1, ip, res);
        }
        else{
    
    
            int next = ip.back() * 10 + (s[index] - '0');
            if(next <= 255 && ip.back() != 0){
    
    
                ip.back() = next;
                dfs(s, index + 1, ip, res);
                ip.back() /= 10;
            }
            if(ip.size() < 4){
    
    
                ip.push_back(s[index] - '0');
                dfs(s, index + 1, ip, res);
                ip.pop_back();
            }
        }
    }

    string get_string(const vector<int>& ip){
    
    
        string res = to_string(ip[0]);
        for(int i = 1; i < ip.size(); i ++)
            res += "." + to_string(ip[i]);
        return res;
    }
};
  1. (131分割回文串) 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。

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

    示例:

    输入: "aab"
    输出:
    [
      ["aa","b"],
      ["a","a","b"]
    ]
    
    
    

排列问题

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

示例:

输入: [1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]
// Perms{nums[0,n-1]} = {取出一个数} + Perms{nums[0,n-1]-这个数})
class Solution {
    
    
private:
    vector<vector<int>> res;
    vector<bool> used;
    
    // 对第indexs个数,根据used数组从nums中选择一个数字加入到n中
    void generatePermutation(vector<int>& nums, int index, vector<int> &n){
    
    
    	if(index==nums.size()){
    
    
            res.push_back(n);
            return;
        }
        
        for(int i=0;i<nums.size();i++){
    
    
            if(!used[i]){
    
    
                n.push_back(nums[i]);
                used[i]=true;
                generatePermutation(nums, index+1, n);
                // 状态恢复
                n.pop_back();
                used[i]=false;
            }
        }
        return;
    }
public:
    vector<vector<int>> permute(vector<int>& nums) {
    
    
        res.clear();
        if(nums.size()==0)
            return res;
        used=vector<bool>(nums.size(), false);
        
        vector<int> p;
        generatePermutation(nums, 0, p);
        return res;
    }
};
  1. (47全排列II) 给定一个可包含重复数字的序列,返回所有不重复的全排列。

    示例:

    输入: [1,1,2]
    输出:
    [
      [1,1,2],
      [1,2,1],
      [2,1,1]
    ]
    
    /// Most Naive Recursive
    /// Time Complexity: O(n^n)
    /// Space Complexity: O(n)
    class Solution {
    
    
    
    private:
        vector<vector<int>> res;
        vector<bool> used;
    
    public:
        vector<vector<int>> permuteUnique(vector<int>& nums) {
    
    
    
            res.clear();
            if(nums.size() == 0)
                return res;
    
            used = vector<bool>(nums.size(), false);
            sort(nums.begin(), nums.end());
            vector<int> p;
    
            generatePermutation(nums, 0, p);
    
            return res;
        }
    
    private:
        void generatePermutation(const vector<int>& nums, int index, vector<int> &p){
    
    
    
            if(index == nums.size()){
    
    
                res.push_back(p);
                return;
            }
    
            for(int i = 0 ; i < nums.size() ; i ++)
                if(!used[i]){
    
    
                    if(i > 0 && nums[i] == nums[i-1] && !used[i-1])
                        continue;
                    p.push_back(nums[i]);
                    used[i] = true;
    
                    generatePermutation(nums, index + 1, p);
    
                    p.pop_back();
                    used[i] = false;
                }
    
        }
    };

组合问题

  1. (77 组合) 给定两个整数 nk,返回 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;
    
    // 求解C(n,k) 已经找到的组合存放在c中,从start开始搜索新的元素
    void findCombination(int n, int k, int start, vector<int> &c){
    
    
        if(c.size()==k){
    
    
            res.push_back(c);
            return;
        }
        // [i,n]中至少要有k-c.size()个元素
        for(int i=start;i<=(n-(k-c.size())+1);i++){
    
    // 一步优化
            c.push_back(i);
            findCombination(n, k, i+1, c);
            c.pop_back();
        }
        
        return;
    }
public:
    vector<vector<int>> combine(int n, int k) {
    
    
        res.clear();
        if(n<1 || k<1 ||k>n)
            return res;
        
        vector<int> p;
        findCombination(n, k, 1, p);
        
        return res;
    }
};
  1. (39组合总和) 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字可以无限制重复被选取。

    说明:

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

    示例:

    输入:candidates = [2,3,6,7], target = 7,
    所求解集为:
    [
      [7],
      [2,2,3]
    ]
    
        /// Time Complexity: O(n^n)
        /// Space Complexity: O(target)
        class Solution {
          
          
        
        public:
            vector<vector<int>> combinationSum(vector<int> &candidates, int target) {
          
          
        
                vector<vector<int>> res;
                vector<int> cur_res;
                solve(candidates, 0, target, cur_res, res);
                return res;
            }
        
        private:
            void solve(const vector<int> &candidates, int index, int target,
                        vector<int>& cur_res, vector<vector<int>>& res){
          
          
        
                if(target == 0){
          
          
                    res.push_back(cur_res);
                    return;
                }
        
                for(int i = index ; i < candidates.size() ; i ++)
                    if(target >= candidates[i]){
          
          
                        cur_res.push_back(candidates[i]);
                        solve(candidates, i, target - candidates[i], cur_res, res);
                        cur_res.pop_back();
                    }
        
                return;
            }
        };
    
  2. (40组合总和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]
    ]
    
        class Solution {
          
          
        
        public:
            vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
          
          
        
                sort(candidates.begin(), candidates.end());
        
                vector<vector<int>> res;
                vector<int> cur_res;
                solve(candidates, 0, target, cur_res, res);
                return res;
            }
        
        private:
            void solve(const vector<int> &candidates, int index, int target,
                       vector<int>& cur_res, vector<vector<int>>& res){
          
          
        
                if(target == 0){
          
          
                    res.push_back(cur_res);
                    return;
                }
        
                for(int i = index ; i < candidates.size() ; i ++){
          
          
                    if(i > index && candidates[i] == candidates[i-1])
                        continue;
                    if(target >= candidates[i]){
          
          
                        cur_res.push_back(candidates[i]);
                        solve(candidates, i + 1, target - candidates[i], cur_res, res);
                        cur_res.pop_back();
                    }
                }
        
                return;
            }
        };
    
  3. (216组合总和) 找出所有相加之和为 nk* 个数的组合**。***组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

    示例 1:

    输入: k = 3, n = 7
    输出: [[1,2,4]]
    
        class Solution {
          
          
        public:
            vector<vector<int>> combinationSum3(int k, int n) {
          
          
        
                vector<vector<int>> res;
                vector<int> cur_res;
                solve(1, k, n, cur_res, res);
                return res;
            }
        
        private:
            void solve(int index, int k, int n,
                       vector<int>& cur_res, vector<vector<int>>& res){
          
          
        
                if(n == 0 && k == 0){
          
          
                    res.push_back(cur_res);
                    return;
                }
        
                if(k == 0)
                    return;
        
                for(int i = index ; i <= 9 ; i ++)
                    if(n >= i){
          
          
                        cur_res.push_back(i);
                        solve(i + 1, k - 1, n - i, cur_res, res);
                        cur_res.pop_back();
                    }
        
                return;
            }
        };
    
  4. (78子集) 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

    示例:

    输入: nums = [1,2,3]
    输出:
    [
      [3],
      [1],
      [2],
      [1,2,3],
      [1,3],
      [2,3],
      [1,2],
      []
    ]
    
  5. (90子集II) 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

    示例:

    输入: [1,2,2]
    输出:
    [
      [2],
      [1],
      [1,2,2],
      [2,2],
      [1,2],
      []
    ]
    
  6. (401二进制手表)二进制手表顶部有 4 个 LED 代表 小时(0-11),底部的 6 个 LED 代表 分钟(0-59)

    每个 LED 代表一个 0 或 1,最低位在右侧。

例如,上面的二进制手表读取 “3:25”。 给定一个非负整数 *n* 代表当前 LED 亮着的数量,返回所有可能的时间。

示例:
输入: n = 1
返回: [“1:00”, “2:00”, “4:00”, “8:00”, “0:01”, “0:02”, “0:04”, “0:08”, “0:16”, “0:32”]

     class Solution {
    
    
     
     public:
         vector<string> readBinaryWatch(int num) {
    
    
     
             vector<string> res;
             vector<bool> bits(10, false);
             go(bits, 0, num, res);
             return res;
         }
     
     private:
         void go(vector<bool>& bits, int index, int num, vector<string>& res){
    
    
     
             if(index == 10){
    
    
                 int h = 0;
                 for(int i = 0; i < 4; i ++) h = h * 2 + bits[i];
     
                 int m = 0;
                 for(int i = 4; i < 10; i ++) m = m * 2 + bits[i];
     
                 if(h < 12 && m < 60){
    
    
                     stringstream ss;
                     ss << h << ":" << setfill('0') << setw(2) << m;
                     res.push_back(ss.str());
                 }
     
                 return;
             }
     
             if(10 - index > num) go(bits, index + 1, num, res);
             if(num){
    
    
                 bits[index] = true;
                 go(bits, index + 1, num - 1, res);
                 bits[index] = false;
             }
             return;
         }
     };
  1. (79 单词搜索) 给定一个二维网格和一个单词,找出该单词是否存在于网格中。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

    示例:

    board =
    [
      ['A','B','C','E'],
      ['S','F','C','S'],
      ['A','D','E','E']
    ]
    给定 word = "ABCCED", 返回 true
    给定 word = "SEE", 返回 true
    给定 word = "ABCB", 返回 false
    
         class Solution {
          
          
         private:
         	int t[2][4] = {
          
           -1,0,1,0,
         				 0,1,0,-1 };
         	vector<vector<bool>> used;
         
         	// 在board[pos_i][pos_j]位置处,找到word[k]
         	bool findPath(vector<vector<char>>& board, string& word, int pos_i, int pos_j, int k) {
          
          
         		if (k == word.size())
         			return true;
         
         		for (int i = 0; i < 4; i++) {
          
          
         			int next_i = pos_i + t[0][i];
         			int next_j = pos_j + t[1][i];
         			if (next_i < 0 || next_i >= board.size() || next_j < 0 || next_j >= board[0].size())
         				continue;
         			if (used[next_i][next_j])
         				continue;
         			if (board[next_i][next_j] == word[k]) {
          
          
         				used[next_i][next_j] = true;
         				if (findPath(board, word, next_i, next_j, k + 1))
         					return true;
         				used[next_i][next_j] = false;
         			}
         		}
         		return false;
         	}
         public:
         	bool exist(vector<vector<char>>& board, string word) {
          
          
         		if (board.size() == 0)
         			return false;
         
         		used = vector<vector<bool>>(board.size(), vector<bool>(board[0].size(), false));
         
         		bool ret = false;
         		for (int i = 0; i < board.size(); i++)
         		for (int j = 0; j < board[i].size(); j++)
         				if (board[i][j] == word[0]) {
          
          
         					used[i][j] = true;
         					if (findPath(board, word, i, j, 1))
         						return true;
         					used[i][j] = false;
         				}
         
         		return ret;
         	}
         };
    
  2. (200 岛屿数量) 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

    示例 :

    输入:
    11000
    11000
    00100
    00011
    
    输出: 3
    
         class Solution {
          
          
         private:
             int m,n;
             int num;
             int d[4][2]={
          
          {
          
          -1,0},{
          
          0,1},{
          
          1,0},{
          
          0,-1}};
             vector<vector<bool> visited;
             
             bool inArea(int &x, int &y){
          
          
                 return (x>=0 && x < m && y>=0 && y<n);
             }
             
             // 以pos_i,pos_j为起点,将与其相连的陆地的visited置为true
             bool findIsland(vector<vector<char>>& grid, int &pos_i, int &pos_j){
          
          
                 if(grid[pos_i][pos_j]=='0')
                     return false;
                 if(vistited[pos_i][pos_j])
                     return false;
                 
                 visited[pos_i][pos_j]=true;
                 
                 for(int i=0;i<4;i++){
          
          
         			int next_i=pos_i+d[i][0];
                     int next_j=pos_j+d[i][1];
                     if(inArea(next_i, next_j) && !visited[next_i][next_j] && findIsland(grid, next_i, next_j)
                        return true;
                 }
                 return false;
             }
         public:
             int numIslands(vector<vector<char>>& grid) {
          
          
         		if(grid.size()==0)
                     return 0;
                 
                 m=grid.size();
                 n=grid[0].size();
                 
                 visited=vector<vector<bool>>(m, vector<bool>(n, false));
                 num=0;
                 
                 for(int i=0;i<m;i++)
                     for(int j=0;j<n;j++)
                         if(findIsLand(grid, i, j))
                             num++;
                 
                 return num;
             }
         };
    
  3. (130被围绕的区域) 给定一个二维的矩阵,包含 'X''O'字母 O)。

    找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O''X' 填充。

    示例:

    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'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

         /// BFS
         /// Time Complexity: O(m*n)
         /// Space Complexity: O(m*n)
         class Solution {
          
          
         private:
             int m, n;
             int d[4][2] = {
          
          {
          
          0,1}, {
          
          1,0}, {
          
          0,-1}, {
          
          -1,0}};
         
         private:
             bool inArea(int x, int y){
          
          
                 return x >= 0 && y >= 0 && x < m && y < n;
             }
         
             bool bfs(const vector<vector<char>> &board, int x, int y, vector<vector<bool>>& visited, vector<pair<int,int>>& record){
          
          
         
                 queue<pair<int,int>> q;
         
                 // return true if we can only get to 'X' during BFS,
                 // otherwise, return false
                 bool ret = true;
         
                 visited[x][y] = true;
                 q.push(pair<int,int>(x, y));
                 while( !q.empty()){
          
          
                     pair<int, int> cur = q.front();
                     q.pop();
                     record.push_back(pair<int, int>(cur.first, cur.second));
         
                     for(int i = 0 ; i < 4 ;i ++){
          
          
                         int newX = cur.first + d[i][0];
                         int newY = cur.second + d[i][1];
         
                         if(!inArea(newX, newY))
                             // If newX, newY is not in the area,
                             // it means we get out of the board in this BFS,
                             // we need to return false in this case
                             ret = false;
                         else if(board[newX][newY] == 'O' && !visited[newX][newY]){
          
          
                             visited[newX][newY] = true;
                             q.push(pair<int, int>(newX, newY));
                         }
                     }
                 }
         
                 return ret;
             }
         
         public:
             void solve(vector<vector<char>>& board) {
          
          
                 m = board.size();
                 if(m == 0)
                     return;
                 n = board[0].size();
                 if(n == 0)
                     return;
         
                 vector<vector<bool>> visited(m, vector<bool>(n, false));
                 vector<pair<int,int>> record;
                 for (int i = 0; i < m; i++)
                     for (int j = 0; j < n; j++)
                         if (board[i][j] == 'O' && !visited[i][j]){
          
          
                             // clear record before each time we run BFS
                             record.clear();
                             if(bfs(board, i, j, visited, record))
                                 // If BFS return true,
                                 // means from this position,
                                 // we will not get out of the board.
                                 // As a result, we can make every position we visited in this BFS from 'O' to 'X'
                                 for(int k = 0 ; k < record.size() ; k ++)
                                     board[record[k].first][record[k].second] = 'X';
                         }
         
                 return;
             }
         };
    
  4. (417太平洋大西洋水流问题) 给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。

    规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。

    请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。

    提示:

    1. 输出坐标的顺序不重要
    2. mn 都小于150

    示例:

    给定下面的 5x5 矩阵:
    
      太平洋 ~   ~   ~   ~   ~ 
           ~  1   2   2   3  (5) *
           ~  3   2   3  (4) (4) *
           ~  2   4  (5)  3   1  *
           ~ (6) (7)  1   4   5  *
           ~ (5)  1   1   2   4  *
              *   *   *   *   * 大西洋
    
    返回:
    
    [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (上图中带括号的单元).
    
         /// Floodfill
         /// Time Complexity: O(m*n)
         /// Space Complexity: O(m*n)
         class Solution {
          
          
         
             private int n, m;
             private boolean[][] pacific, atlantic;
             private int[][] d = {
          
          {
          
          0, 1}, {
          
          0, -1}, {
          
          1, 0}, {
          
          -1, 0}};
         
             public List<int[]> pacificAtlantic(int[][] matrix) {
          
          
         
                 ArrayList<int[]> res = new ArrayList<>();
         
                 n = matrix.length;
                 if(n == 0)
                     return res;
                 m = matrix[0].length;
         
                 pacific = new boolean[n][m];
                 atlantic = new boolean[n][m];
         
                 for(int i = 0 ; i < n ; i ++){
          
          
                     dfs(matrix, pacific, i, 0);
                     dfs(matrix, atlantic, i, m - 1);
                 }
         
                 for(int j = 0 ; j < m ; j ++){
          
          
                     dfs(matrix, pacific, 0, j);
                     dfs(matrix, atlantic, n - 1, j);
                 }
         
                 for(int i = 0 ; i < n ; i ++)
                     for(int j = 0 ; j < m ; j ++)
                         if(pacific[i][j] && atlantic[i][j])
                             res.add(new int[]{
          
          i, j});
                 return res;
             }
         
             private void dfs(int[][] matrix, boolean[][] visited, int x, int y){
          
          
         
                 visited[x][y] = true;
                 for(int i = 0 ; i < 4 ; i ++){
          
          
                     int newX = x + d[i][0];
                     int newY = y + d[i][1];
                     if(inArea(newX, newY) && !visited[newX][newY] && matrix[newX][newY] >= matrix[x][y])
                         dfs(matrix, visited, newX, newY);
                 }
             }
         
             private boolean inArea(int x, int y){
          
          
                 return x >= 0 && x < n && y >= 0 && y < m;
             }
         
             public static void printList(List<int[]> list){
          
          
                 for(int[] e: list)
                     System.out.print("[ " + e[0] + " , " + e[1] + " ] ");
                 System.out.println();
             }
    
  5. (51 N皇后) n皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

    img

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

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

示例:

输入: 4
输出: [
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],
  ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
class Solution {
    
    
private:
	vector<vector<string>> res;
	vector<string> one_res;
	vector<bool> row;
	vector<bool> col;
	vector<bool> dia1;
	vector<bool> dia2;

	// 对于第index个皇后,尝试在第index行的c列摆放
	void findSolution(int n, int index, int c) {
    
    
		if (index >= n) {
    
    
			res.push_back(one_res);
			return;
		}

		if (row[index] || col[c] || dia1[index + c] || dia2[index - c + n - 1])
			return;

		row[index] = true;
		col[c] = true;
		dia1[index + c] = true;
		dia2[index - c + n - 1] = true;
		one_res[index][c] = 'Q';

		for (int i = 0; i < n; i++) {
    
    
			findSolution(n, index + 1, i);
			if (index + 1 >= n)
				break;
		}
		row[index] = false;
		col[c] = false;
		dia1[index + c] = false;
		dia2[index - c + n - 1] = false;
		one_res[index][c] = '.';
		return;
	}
public:
	vector<vector<string>> solveNQueens(int n) {
    
    
		if (n == 0)
			return res;

		row = vector<bool>(n, false);
		col = vector<bool>(n, false);
		dia1 = vector<bool>(2 * n - 1, false);
		dia2 = vector<bool>(2 * n - 1, false);
		one_res = vector<string>(n, string(n, '.'));

		for (int i = 0; i < n; i++)
			findSolution(n, 0, i);

		return res;
	}
};
  1. (37解数独) 编写一个程序,通过填充空格来解决数独问题。

img

img

/// Backtracking
/// Time Complexity: O(n^{need to fill})
/// Space Complexity: O(9*9)
class Solution {
    
    
public:
    void solveSudoku(vector<vector<char>>& board) {
    
    

        vector<vector<bool>> row(9, vector<bool>(10, false));
        vector<vector<bool>> col(9, vector<bool>(10, false));
        vector<vector<bool>> block(9, vector<bool>(10, false));
        for(int i = 0; i < 9; i ++)
            for(int j = 0; j < 9; j ++)
                if(board[i][j] != '.'){
    
    
                    row[i][board[i][j] - '0'] = true;
                    col[j][board[i][j] - '0'] = true;
                    block[i / 3 * 3 + j / 3][board[i][j] - '0'] = true;
                }

        for(int i = 0; i < 81; i ++)
            if(board[i / 9][i % 9] == '.'){
    
    
                assert(dfs(board, i, row, col, block));
                return;
            }
    }

private:
    bool dfs(vector<vector<char>>& board, int pos,
             vector<vector<bool>>& row, vector<vector<bool>>& col,
             vector<vector<bool>>& block){
    
    

        if(pos == 81)
            return true;

        int next = pos + 1;
        for(; next < 81; next ++)
            if(board[next / 9][next % 9] == '.')
                break;

        int x = pos / 9, y = pos % 9;
        for(int i = 1; i <= 9; i ++)
            if(!row[x][i] && !col[y][i] && !block[x / 3 * 3 + y / 3][i]){
    
    
                row[x][i] = true;
                col[y][i] = true;
                block[x / 3 * 3 + y / 3][i] = true;
                board[x][y] = '0' + i;

                if(dfs(board, next, row, col, block))
                    return true;

                row[x][i] = false;
                col[y][i] = false;
                block[x / 3 * 3 + y / 3][i] = false;
                board[x][y] = '.';
            }
        return false;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_34731182/article/details/113643007