回溯-剑指 Offer 38. 字符串的排列

147 阅读1分钟

题目链接

  • 输入一个字符串,打印出该字符串中字符的所有排列。
  • 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。

思路

  • 本题是全排列问题,使用回溯+深度优先的思想
  • 当元素遍历完,则添加进res列表
  • s中有重复字符,要考虑去重问题 - 剪枝
    • s排序
    • 用set记录处理过的字符

代码实现

不考虑重复字符

class Solution:
    def permutation(self, s: str) -> List[str]:
        res = []
        s = list(s)
        def dfs(s, tmp):
            if not s:
                res.append(''.join(tmp))
                return
            for i, letter in enumerate(s):
                dfs(s[:i] + s[i+1:], tmp + [letter])
        dfs(s, [])
        return res

考虑重复字符

  • s先排序,当发现相邻字符重复,则跳过当前处理的字符
class Solution:
    def permutation(self, s: str) -> List[str]:
        res = []
        s = list(sorted(s))
        def dfs(s, tmp):
            if not s:
                res.append(''.join(tmp))
                return
            for i, letter in enumerate(s):
                if i > 0 and s[i] == s[i-1]: continue
                dfs(s[:i] + s[i+1:], tmp + [letter])
        dfs(s, [])
        return res
  • 使用set解决重复问题

详解

class Solution:
    def permutation(self, s: str) -> List[str]:
        c, res = list(s), []
        def dfs(x):
            if x == len(c) - 1:
                res.append(''.join(c)) # 添加排列方案
                return
            dic = set()
            for i in range(x, len(c)):
                if c[i] in dic: continue # 重复,因此剪枝
                dic.add(c[i])
                c[i], c[x] = c[x], c[i] # 交换,将 c[i] 固定在第 x 位
                dfs(x + 1) # 开启固定第 x + 1 位字符
                c[i], c[x] = c[x], c[i] # 恢复交换
        dfs(0)
        return res
  • 此题目可以扩展为数字的全排列
class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        res=[]
        nums.sort()
        def helper(nums,temp):
            if not nums:
                res.append(temp)
            for i in range(len(nums)):
                if i>0 and nums[i]==nums[i-1]:
                    continue
                helper(nums[:i]+nums[i+1:],temp+[nums[i]])
        helper(nums,[])
        return res