前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一天一大 lee(全排列 II)难度:中等-Day20200918

一天一大 lee(全排列 II)难度:中等-Day20200918

作者头像
前端小书童
发布2020-09-24 14:34:37
2710
发布2020-09-24 14:34:37
举报

题目:[1]

给定一个可包含重复数字的序列,返回所有不重复的全排列。

示例:

输入: [1,1,2]
输出:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]

抛砖引玉

抛砖引玉

在全排列中,处理过对一个数组的元素重新进行排列,但是全排列中限制了没有重复的元素:全排列[2]

本题中包含重复的元素,则在枚举的过程中,即使从不同位置取元素组合,也可能形成相同的组合。

那么本题的重点就成了如何避免形成重复的组合了:

  1. 记录选择是不能使用值作为记录的标记需要使用索引
  2. 重复元素合并参与索引选择-回溯时只参与一次:
    • 注意此处并不会有元素不能被选中,例如两个连续的1:
    • 第一个1在某次枚举时被选中,第二个1不再参与选择-回溯
    • 第二个1形成的组合在第一个1不再某次被选中是触发(第二个1的选择-回溯)

回溯-记录选择

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permuteUnique = function(nums) {
  let _result = [],
    inList = new Map()
  function helper(item) {
    if (item.length === nums.length) {
      _result.push([...item])
      return
    }
    for (let i = 0; i < nums.length; i++) {
      // 增加重复元素判断,如果元素与上一个相邻元素相同,那么这两个相邻元素只有一个可以参与位置的选择-回溯
      if (inList.has(i) || (i > 0 && nums[i] === nums[i - 1] && !inList.has(i-1))) continue
      item.push(nums[i])
      inList.set(i, true)
      helper(item)
      // 回溯-释放上面被在该位置选择的元素尝试在该位置选择其他元素
      item.pop()
      inList.delete(i)
    }
  }
   if (nums.length < 2) return nums.length === 1 ? [nums]: _result
  //  排序是重复元素相邻
  nums.sort((a, b) => a - b)
  helper([])
  return _result
}

回溯-位置交换

  • 在交换位置的逻辑中两次拿相同的元素与其他元素交互最后形成的组合是相同的
  • 那么在每次拿一个元素枚举其他位置与其交换时,记录已经交换过的元素,如果再次遇到已经交换过的元素则不再交互

注意: 上面交换重复的逻辑至少针对一轮交换,即针对一个索引位置的交换,更新要交换的位置后,去重的逻辑需要重新开始

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function(nums) {
  let _result = []
  if (nums.length < 2) return nums.length === 1 ? [nums]: _result
  function helper(index) {
    if (index === nums.length) {
      _result.push([...nums])
      return
    }
    let map = new Map();
    for (let i = index; i < nums.length; i++) {
      // 一轮交换(一个新位置)中只有未交换过的元素才能参与交换
      if(!map.has(nums[i])) {
        map.set(nums[i], true);
        // 逐个与当前索引位元素交换
        swap(nums, i, index)
        // 进行后续交换
        helper(index + 1)
        // 回溯上一次交换,让下一个位置的交换在上一次未交换的基础上开始
        swap(nums, i, index)
      }
    }
  }
  // 替换指定位置两个数
  function swap(a, i, j) {
    var tmp = a[i]
    a[i] = a[j]
    a[j] = tmp
  }
  helper(0)
  return _result
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-09-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端小书童 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 示例:
  • 抛砖引玉
    • 回溯-记录选择
      • 回溯-位置交换
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档