美文网首页算法
回溯一:全排列、子集

回溯一:全排列、子集

作者: 某非著名程序员 | 来源:发表于2021-01-16 10:08 被阅读0次

46. 全排列
47. 全排列 II
78. 子集
90. 子集 II

46. 全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。
输入: [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

思路

递归就像一棵树,画出树状图,比较好理解。


全排列.png

代码

func permute(_ nums: [Int]) -> [[Int]] {
            var res = [[Int]]()
            var subres = [Int]()
            var used = Array.init(repeating: false, count: nums.count)
            
            dfs(nums, 0,&used,&res,&subres)
            return res
        }
        
        func dfs(_ nums: [Int],_ idx:Int,_ used:inout [Bool],_ res:inout [[Int]],_ subres:inout [Int]) {
            if idx == nums.count {
                res.append(subres)
                return
            }
            
            for i in 0..<nums.count {
                if used[i] {
                    continue
                }
                used[i] = true
                subres.append(nums[i])
                
                dfs(nums, idx+1, &used,&res,&subres)
                
                subres.removeLast()
                used[i] = false
            }
        }

47. 全排列 II

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

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

思路

与全排列1不同的是,有重复数字需要去重。
1.先排序,加去重条件
2.一张图看懂剪枝


全排列2剪枝.png

func permuteUnique(_ nums: [Int]) -> [[Int]] {
        var ans = [[Int]]()
        var subans = [Int]()
        
        var nums = nums.sorted()
        var used = Array.init(repeating: false, count: nums.count)
        
        dfs(&nums, &ans, 0,&used,&subans)
        return ans
    }
    
    func dfs(_ nums: inout [Int],_ ans:inout [[Int]],_ idx:Int,_ used:inout [Bool],_ subans:inout [Int]) {
        if idx == nums.count {
            ans.append(subans)
            return
        }
        
        for i in 0..<nums.count {
            if used[i] {
                continue
            }
            
            if i>0 && nums[i] == nums[i-1] && !used[i-1]{
                continue
            }
            
            subans.append(nums[i])
            used[i] = true
            
            dfs(&nums, &ans, idx+1, &used, &subans)
            
            subans.removeLast()
            used[i] = false
        }
    }

78. 子集

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

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

思路

子集与全排列不同的地方:
dfs(&nums, &ans, idx+1, &used, &subans)
dfs(nums, i+1, &ans, &subans,&used)
读者可自己画出树状图进行理解

代码

//给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
        func subsets(_ nums: [Int]) -> [[Int]] {
            var ans = [[Int]]()
            var subans = [Int]()
            var used = Array.init(repeating: false, count: nums.count)

            dfs(nums,0,&ans,&subans,&used)
            return ans
        }

        func dfs(_ nums:[Int],_ idx:Int,_ ans:inout [[Int]],_ subans:inout [Int],_ used:inout [Bool]) {
            ans.append(subans)
            for i in idx..<nums.count {
                if used[i] {
                    continue
                }
                used[i] = true
                subans.append(nums[i])
                dfs(nums, i+1, &ans, &subans,&used)
                subans.removeLast()
                used[i] = false
            }
        }

90. 子集 II

与全排列2基本一样,递归由idx变成了i。

func subsetsWithDup(_ nums: [Int]) -> [[Int]] {
            let nums = nums.sorted()
            
            var ans = [[Int]]()
            var subans = [Int]()
            var used = Array.init(repeating: false, count: nums.count)

            dfs(nums,0,&ans,&subans,&used)
            return ans
        }
        
        func dfs(_ nums:[Int],_ idx:Int,_ ans:inout [[Int]],_ subans:inout [Int],_ used:inout [Bool]) {
            ans.append(subans)
            for i in idx..<nums.count {
                if used[i] {
                    continue
                }
                if i>0 && nums[i] == nums[i-1] && !used[i-1]{//前一个元素没有选过的
                    continue
                }
                used[i] = true
                subans.append(nums[i])
                dfs(nums, i+1, &ans, &subans,&used)
                subans.removeLast()
                used[i] = false
            }
        }

总结

  1. 排列、子集属于递归非常经典的一类问题
  2. 升级版本就是去重,剪枝

相关文章

  • 回溯一:全排列、子集

    46. 全排列[https://leetcode-cn.com/problems/permutations/]47...

  • 回溯--全排列

    目录[https://www.jianshu.com/p/85e18c21317a] 题号[https://lee...

  • 子集、全排列、第k个排列

    子集输出 全排列输出 存在重复数字的全排列 给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。 按大...

  • 4.2 回溯法(2)

    套路 解决全排列问题可以用到回溯 全排列问题往往可以用交换两位置元素的方法,完成后续步骤后,需要回溯时再交换回原来...

  • 全排列

    回溯实现全排列 给定一组数,如:1,2,3。编程实现全排列形式:123,132,213,231,312,321

  • 排列组合与回溯法

    排列,组合,回溯法 ex.1 ex.2 排列 全排列:从第一个数字起,每个数字分别与它后面的数字交换 去重全排列:...

  • 搜索(二)回溯

    一、题目总结 基础问题 46.全排列 77.组合 78.子集 39.组合求和 47.全排列 II(重复元素) 90...

  • 全排列(LeetCode 46 回溯)

    题目 给定一个没有重复数字的序列,返回其所有可能的全排列。 示例: 输入: [1,2,3]输出:[[1,2,3],...

  • 排列,组合,子集专题

    排列组合的题用回溯法和递归基本可以解决,总结一下。46.全排列 47.全排列II 47比46多了个序列可重复的条件...

  • 「回溯算法」专题介绍

    「回溯算法」专题介绍 第 1 节:从全排列问题开始理解回溯搜索算法 引言 大家好,今天要和大家分享的主题是“回溯算...

网友评论

    本文标题:回溯一:全排列、子集

    本文链接:https://www.haomeiwen.com/subject/ntgmyktx.html