zoukankan      html  css  js  c++  java
  • 回溯算法解题套路框架 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 };

          

  • 相关阅读:
    bootstrap组件+模板地址
    10个自动化测试框架,测试工程师用起来
    IP地址分类(A类 B类 C类 D类 E类)
    来不及解释!Linux常用命令大全,先收藏再说
    凭借祖传配方年入21亿(王守义十三香),一生坚持不上市,亏待自己也要善待员工
    不同手指戴戒指的含义
    Soul App 是一款怎样的产品? SOUL APP 机缘巧合我开始使用 今天第四天内心想知道大家对它的感受 又其实并没有那么想大家把感受具象化再描述出来 嗯 还是希望大家能说一说(网恋需谨慎,小心骗子)
    解放双手,markdown文章神器,Typora+PicGo+七牛云图床实现自动上传图片
    度学习与自然语言处理
    软件测试面试之剖析面试官
  • 原文地址:https://www.cnblogs.com/wangxf2019/p/13960646.html
Copyright © 2011-2022 走看看