12.15 回溯算法 - leetcode 491递增子序列 / 46 全排列 / 47 全排列 II

Leetcode 491: 递增子序列

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。

数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况

示例 1:
输入:nums = [4,6,7,7]
输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]

示例 2:
输入:nums = [4,4,3,2,1]
输出:[[4,4]]

回溯三部曲

  1. 递归函数参数
    本题求子序列, 很明显当前元素不能重复使用, 需要 start 去控制下一次递归 for循环 的起始位置.
let result = [] // 最终输出的结果
let temp = [] // 记录单次符合的结果
const backtracking = (start)
  1. 递归终止条件
  • 可以不加终止条件, 因为 start 每次都会递归加1, 当超过给出数组长度就不会再进行递归
  • 收集结果: 题目中给出至少需要两个元素, 那么当 temp 的长度大于1的时候便推入 result
if(temp.length > 1){
  result.push([...temp]) // 拷贝一份
}
  1. 单层搜索逻辑
  • 同一父节点下, 同一层级使用过的元素就不能再使用了 -> 需要每层遍历的时候创建一个 Set, 记录每个元素, 如果相同, 则 continue (Set没有对应的pop是因为新的一层会重新定义, 起到清空效果)
  • 递增子序列, 需要验证新元素和是否大于 temp 末尾的元素, 如果新元素更小, 则 continue
if(temp.length > 0 && nums[i] < temp[temp.length - 1] || uset.has(nums[i])) continue
  temp.push(nums[i])
  uset.add(nums[i])
  backtracking(i + 1)
  temp.pop()
}

完整代码

var findSubsequences = function(nums) {
  const result = []
  const temp = []
  const backtracking = (start) => {
    if(temp.length >= 2){
      result.push([...temp])
    }
    const uset = new Set()
    for(let i = start; i < nums.length; i++){
      // 情况(||): 可能这一个数字并不比前一个小,但是重复了,需要continue
      if(temp.length > 0 && nums[i] < temp[temp.length - 1] || uset.has(nums[i])) continue
      temp.push(nums[i])
      uset.add(nums[i])
      backtracking(i + 1)
      temp.pop()
    }
  }

  backtracking(0)
  return result
};

Leetcode 46: 全排列

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

示例 2:
输入:nums = [0,1]
输出:[[0,1],[1,0]]

回溯三部曲

  1. 递归函数参数
  • 本题不需要 start, 因为集合 [1, 2] 和 [2, 1] 是两个集合, 也就是说1要在两个集合中都使用
  • 需要一个 used 数组, 每次推入 temp 集合中的元素下表设置为1, 下次递归的时候便可以排除
  const result = []
  const temp = []
  const used = new Array(nums.length).fill(0)
  1. 递归终止条件
    如果 temp 的数组和 nums 的数组长度一致, 则推入到 result
  if(temp.length === nums.length){
    result.push([...temp])
  }
  1. 单层搜索逻辑
  • 判断如果 used[i] = 1, 表明当前元素已加入到 temp 里, 需要过滤掉
  • 添加新元素的时候需要设置 used[i] = 1
  for(let i = 0; i < nums.length; i++){
    if(used[i] === 1) continue
    temp.push(nums[i])
    used[i] = 1
    backtracking()
    used[i] = 0
    temp.pop()
  }

完整代码

var permute = function(nums) {
  const result = []
  const temp = []
  const used = new Array(nums.length).fill(0)
  const backtracking = () => {
    if(temp.length === nums.length){
      result.push([...temp])
    }

    for(let i = 0; i < nums.length; i++){
      if(used[i] === 1) continue
      temp.push(nums[i])
      used[i] = 1
      backtracking()
      used[i] = 0
      temp.pop()
    }
  }
  backtracking()
  return result
};

Leetcode 46: 全排列 II

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

示例 1:
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]

示例 2:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

回溯三部曲

  1. 递归函数参数
  • 需要一个 used 数组, 每次推入 temp 集合中的元素下表设置为1, 下次递归的时候便可以排除
  • 每层需要一个 set 来排除同层级使用过的元素
  const result = []
  const temp = []
  const used = new Array(nums.length).fill(0)
  1. 递归终止条件
    如果 temp 的数组和 nums 的数组长度一致, 则推入到 result
  if(temp.length === nums.length){
    result.push([...temp])
  }
  1. 单层搜索逻辑
  • 判断如果 used[i] = 1, 表明当前元素已加入到 temp 里, 需要过滤掉
  • 如果 set 里已经包含这个元素, 则过滤掉
  for(let i = 0; i < nums.length; i++){
    if(used[i] === 1) continue
    temp.push(nums[i])
    used[i] = 1
    backtracking()
    used[i] = 0
    temp.pop()
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值