算法套路-深度优先搜索中的排列组合

目录

0 文章介绍

1 dfs套路

2 排列

2.1 给定数组,无重复数,不重复用的排列

2.2 给定数组,有重复数,不重复用的排列

2.3 给定数组,无重复数,可重复用的排列

3 组合

3.1 给定数组,无重复数,不重复用的组合

3.2 给定数组,无重复数,可重复用的组合

3.3 给定数组,有重复数,不重复用的组合(难)


0 文章介绍

本文使用python语言,以leetcode里的题目来介绍算法中使用深度优先搜索的排列组合问题。

我把排列和组合分别分成3种情况

  1. 无重复数,不重复用
  2. 无重复数,可重复用
  3. 有重复数,不重复用

根据排列组合,应该是4种啊,还有有重复数,可重复用啊,这种情况,先把重复数去重,就转换回第3种情况了

1 dfs套路

对于每一种情况x:
	dfs(x)
  
def dfs(x):
	if 情况x不满足当前条件:
      return
    
    if x是最后一个元素了:
      搜到了,做操作
      return
    
    标记x情况搜过了
    for y in 由x衍生出的其他条件:
      dfs(y)
    标记x情况没搜过

 

2 排列

2.1 给定数组,无重复数,不重复用的排列

可以把数组调换顺序

46. 全排列 - 力扣(LeetCode)

题意:给定没有重复数字的数组,返回所有排列的情况

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        def dfs(i):
            if i==n: ans.append(nums.copy())
            for x in range(i,n):
                nums[i],nums[x]=nums[x],nums[i]
                dfs(i+1)
                nums[i],nums[x]=nums[x],nums[i]
        n=len(nums)
        ans=[]
        dfs(0)
        return ans

2.2 给定数组,有重复数,不重复用的排列

47. 全排列 II - 力扣(LeetCode) (leetcode-cn.com)

题意:给定有重复数字的数组,返回所有的排列情况

只要确定当前位置这个值没有出现过就行。把元素放进dict,key为元素,value为出现的次数,每次遍历dict就行。

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        def dfs(i):
            if i==n: ans.append(nums.copy())
            for x in range(i,n):
                nums[i],nums[x]=nums[x],nums[i]
                dfs(i+1)
                nums[i],nums[x]=nums[x],nums[i]
        n=len(nums)
        ans=[]
        dfs(0)
        return ans

2.3 给定数组,无重复数,可重复用的排列

377. 组合总和 Ⅳ

这个是完全背包问题,偏题了

题意:给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。

class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        dp=[0]*(target+1)
        dp[0]=1
        for i in range(target+1):
            for num in nums:
                if i>=num:
                    dp[i]+=dp[i-num]
        return dp[target]

3 组合

组合相对排列就简单多了,不需要考虑先后顺序,只考虑有没有这个元素。

3.1 给定数组,无重复数,不重复用的组合

216. 组合总和 III

题意:找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

说明:所有数字都是正整数。解集不能包含重复的组合。 

解答:正常深度优先搜索就行

class Solution:
    def combinationSum3(self, k: int, n: int) -> List[List[int]]:
        def dfs(num,tmpsum):
            if len(tmp)==k:
                if tmpsum==n:ans.append(tmp.copy())
                return
            elif tmpsum>n:return
            for i in range(num,10):
                tmp.append(i)
                dfs(i+1,tmpsum+i)
                tmp.pop()
        ans,tmp=[],[]     
        dfs(1,0)
        return ans

3.2 给定数组,无重复数,可重复用的组合

39. 组合总和

题意:给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字可以无限制重复被选取。

解答:因为可重复选取元素,稍微改造以下深度优先搜索方式即可

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        def dfs(idx,total):
            if total==target:ans.append(tmp.copy())
            elif total>target:return
            for i in range(idx,n):
                tmp.append(candidates[i])
                dfs(i,total+candidates[i])
                tmp.pop()
        candidates.sort()
        n=len(candidates)
        ans,tmp=[],[]
        dfs(0,0)
        return ans

3.3 给定数组,有重复数,不重复用的组合(难)

40. 组合总和 II

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用一次。

解析:本题难点在于如果有1,1,1,3,target=5。组成5的两个1有3种组合方式,但是是一样的,需合并。本题骚操作是,重复的元素只允许第一遍时扫过去。也就是说,组成的元素里有1,且这个1来自第一个1的位置,正常向后搜索。组成的元素里有1,且这个1不是来自第一个1的位置,那就放弃搜索,找到第一个不是1的数字的位置搜索就行。

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        def dfs(idx,total):
            if total>target:return
            elif total==target:
                ans.append(tmp.copy())
                return
            for i in range(idx,n):#重复的只允许第一遍扫过去
                if i>idx and candidates[i]==candidates[i-1]:continue
                tmp.append(candidates[i])
                dfs(i+1,total+candidates[i])
                tmp.pop()
        candidates.sort()
        n=len(candidates)
        tmp,ans=[],[]
        dfs(0,0)
        return ans

猜你喜欢

转载自blog.csdn.net/nanfeizhenkuangou/article/details/111301790
今日推荐