回溯算法解题套路框架 LeetCode 46 全排列1 ; LeetCode 47 全排列 2 ;LeetCode 51 N皇后 ;

搬运 博主 lambdadong 的博客:   labuladong 的算法小抄

回溯算法的框架:

 1 result = []
 2 def backtrack(路径, 选择列表):
 3     if 满足结束条件:
 4     result.add(路径)
 5     return
 6 
 7     # 做选择
 8     将 选择i 从选择列表中移除/标记 选择i 已经选择过
 9     路径.add(选择i)
10     backtrack(路径, 选择列表)
11     # 撤销选择
12     路径.remove(选择1)
13     将该选择i再加回选择列表

一、全排列问题

       1.1  LeetCode 46 全排列1   求没有重复元素的数组的全排列

直接套用框架:

 1 class Solution {
 2 private:
 3     vector<int> path;
 4     vector<vector<int>> res;
 5 public:
 6     vector<vector<int>> permuteUnique(vector<int>& nums) {
 7         //sort(nums.begin(),nums.end());
 8         int len=nums.size();
 9         vector<bool> visited(len,false);
10         backtrack(nums,visited,0);
11         return res;
12     }
13 // 路径:记录在 path 中
14 // 选择列表:visited[i] 为true 的nums[i]
15 // 结束条件:depth == nums.size() 走到"决策树"的叶节点
16     void backtrack(vector<int>& nums,vector<bool>& visited ,int depth) {
17         int len=nums.size();
18         if ( depth == nums.size()) {
19             res.push_back(path);      
20             return;
21         }
22         for (int i=0;i<len;i++) {
23             if (visited[i]) continue;
24             //if (i>0 && nums[i]==nums[i-1] && visited[i-1])  continue;
25             visited[i] = true;
26             path.push_back(nums[i]);
27             backtrack(nums,visited,depth+1);
28             path.pop_back();
29             visited[i] = false;
30         }
31     }
32 };

 

1.2   LeetCode 47 全排列2   求有重复元素的数组的全排列

       在平时项目中遇到这种需求,可以直接使用 c++ STL 的   next_permutation 函数生成所有的排列,

得到的结果就已经是去重过的了,且有很好的效率。 注意使用  next_permutation  前 ,需要 先将数组

排序 。代码如下:  

#include<algrithm>
#include<vector>
using namespace std;

  vector<vector<int>> permuteUnique(vector<int>& nums)
    {
        sort(nums.begin(), nums.end());
        vector<vector<int>>result;
        result.push_back(nums);
        while (next_permutation(nums.begin(), nums.end()))
        {
            result.push_back(nums);
        }
        return result;
    }

     对比 1.1 没有重复的元素,使用1.1 中的代码得到的全排列中会包含重复的排列,可以在得到所有的排列之后,

使用set<vector<int>> 辅助 去重就可。

void remove_repeated_vec(vector<vector<int>> &res)
    {
        set<vector<int>> unique_set;
        vector<vector<int>>::iterator ite;
        vector<vector<int>> tmp_res;
        for(ite = res.begin();ite != res.end();++ite)
        {
            if(unique_set.find(*ite) == unique_set.end())
            {
                unique_set.insert(*ite);
                tmp_res.push_back(*ite);
            }
        }
        res = tmp_res;
        return;
   }

或者直接把  1.1 中 line 7 和 line 24 两处的注释取消,

 

二.   N皇后

 1 class Solution {
 2 public:
 3    vector<vector<string>> res;
 4 
 5     /* 输入棋盘边长 n,返回所有合法的放置 */
 6     vector<vector<string>> solveNQueens(int n)
 7     {
 8         // '.' 表示空,'Q' 表示皇后,初始化空棋盘。
 9         vector<string> board(n, string(n, '.'));
10         backtrack(board, 0);
11         return res;
12     }
13 
14     // 路径:board 中小于 row 的那些行都已经成功放置了皇后
15     // 选择列表:第 row 行的所有列都是放置皇后的选择
16     // 结束条件:row 超过 board 的最后一行
17     void backtrack(vector<string>& board, int row)
18     {
19         // 触发结束条件
20         if (row == board.size()) {
21             res.push_back(board);
22             return;
23         }
24 
25         int n = board[row].size();
26         for (int col = 0; col < n; col++) {
27             // 排除不合法选择
28             if (!isValid(board, row, col)) 
29                 continue;
30             // 做选择
31             board[row][col] = 'Q';
32             // 进入下一行决策
33             backtrack(board, row + 1);
34             // 撤销选择
35             board[row][col] = '.';
36         }
37     }
38 
39     /* 是否可以在 board[row][col] 放置皇后? */
40     bool isValid(vector<string>& board, int row, int col)
41     {
42         int n = board.size();
43         // 检查列是否有皇后互相冲突
44         for (int i = 0; i < n; i++) {
45             if (board[i][col] == 'Q')
46                 return false;
47         }
48         // 检查右上方是否有皇后互相冲突
49         for (int i = row - 1, j = col + 1; 
50                 i >= 0 && j < n; i--, j++) {
51             if (board[i][j] == 'Q')
52                 return false;
53         }
54         // 检查左上方是否有皇后互相冲突
55         for (int i = row - 1, j = col - 1;
56                 i >= 0 && j >= 0; i--, j--) {
57             if (board[i][j] == 'Q')
58                 return false;
59         }
60         return true;
61     }
62 };

 

 

      

posted @ 2020-11-11 20:02  谁在写西加加  阅读(78)  评论(0编辑  收藏  举报