全排列总结

 46. 全排列

 解答过程:

力扣https://leetcode.cn/problems/permutations/solution/chou-xiang-cheng-jue-ce-shu-yi-ge-pai-lie-jiu-xian/

​
/**
 * @param {number[]} nums
 * @return {number[][]}
 递归+回溯
思路
1、每一位都有3种选择:1、2、3。
2、每一次都做选择,展开出一棵空间树,如下图。
3、利用约束条件「不能重复选」,做剪枝,剪去不会产生正确解的选项(分支)。
(1)利用 hashMap,记录选过的数,下次遇到相同的数,跳过。
(2)这样就不会进入「不会得出解的分支」,不做无效的搜索。

【1】结束当前递归时,将它加入 res 后,该算法还要进入别的递归分支继续搜索,还要继续将这个 path 传给别的递归调用,它所指向的内存空间还要继续被操作,所以 res 中的 path 的内容会被改变,这就不对。

 */
var permute = function(nums) {
  const res = [];
  const usedMap = {}; //哈希表,用于记录要选择的数有没有使用过

  // 深度优先遍历的递归函数dfs
  function dfs(path) {
      // 递归出口:选择的路径长度满足了要求,刚好选满
      if(path.length === nums.length) {
          res.push(path.slice()); // 【1】
          return; // 结束当前递归的路径选择
      }
      for(const num of nums) { 
          if(usedMap[num]) continue;  // 使用过的直接跳过,避免无效路径
          path.push(num); // 没有使用过的,加入paht的路径选择
          usedMap[num] = true; // 同时将这个数标记为已使用
          dfs(path); // 在选择了num的当前path路径上继续递归,进行路径选择,直到该条路径的递归结束;
          path.pop(); // 上一条路径的递归结束,回溯:(1)将最后选择的数pop出去(2)将最后一个数的使用状态改为未使用;
          usedMap[num] = false;
      }
  }
  dfs([]); // 递归入口:dfs 执行传入空 path,什么都还没选
  return res;
};

​

 const _permute = string => {
               if(string.length === 1){
                   return [string];
               }
               // 全排列容器
               const res = [];
               for(let s of string) {
                    // 获取除了当前元素外的其他元素字符串
                    const otherStr = string.split('').filter(item => item!==s).join('');
                    // 递归获取其余元素字符串的递归集合,并和当前元素进行拼接
                    _permute(otherStr).forEach(str => {
                        res.push(s + str);
                    })
                }
               return res;
            }

 可以用于字符串的处理,照搬过来用的话,处理不了数组的情况:

 使用上述题目的递归+回溯的解法可以处理该题目,测试用例通过的解答:

    const _permute = string => {
                // 补全代码
               const res = [];
              const usedMap = {}; //哈希表,用于记录要选择的数有没有使用过
 
              // 深度优先遍历的递归函数dfs
              function dfs(path) {
                  // 递归出口:选择的路径长度满足了要求,刚好选满
                  if(path.length === string.length) {
                      res.push(path.slice()); // 【1】
                      return; // 结束当前递归的路径选择
                  }
                  for(const num of string) {
                      if(usedMap[num]) continue;  // 使用过的直接跳过,避免无效路径
                      path.push(num); // 没有使用过的,加入paht的路径选择
                      usedMap[num] = true; // 同时将这个数标记为已使用
                      dfs(path); // 在选择了num的当前path路径上继续递归,进行路径选择,直到该条路径的递归结束;
                      path.pop(); // 上一条路径的递归结束,回溯:(1)将最后选择的数pop出去(2)将最后一个数的使用状态改为未使用;
                      usedMap[num] = false;
                  }
              }
              dfs([]); // 递归入口:dfs 执行传入空 path,什么都还没选
              return res.map(item => item.join(''));
 
            }

猜你喜欢

转载自blog.csdn.net/qq_39207948/article/details/124885457