排列&组合系列--数字、str

排列(数字序列 & str序列)

38 字符串的排列
给定一个 没有重复 数字的序列,返回其所有可能的全排列。输入: [1,2,3]
leecode 46
在这里插入图片描述

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        def dfs(first):  # first 记录每次开始的第一个位置  #[位置 #递归function的 参数是?想清楚很important]
            if first == n: # 当起始位置超越数组长度了,停止,加入结果集
                res.append(nums[:])  # 这里要加入其复制,不然传的是引用,会被后面修改
            for i in range(first, n):  # 第一个数字与后面所有数字依次交换
                nums[first], nums[i] = nums[i], nums[first]
                dfs(first + 1)  # 递归替换下一个位置
                nums[first], nums[i] = nums[i], nums[first]  # 回溯,还原,才能进行下一次交换!

        n = len(nums)
        res = []
        dfs(0)
        return res
#知识点
#python
#深&浅copy之一
nums=[3,6,2]
#test1
a=[]
a.append(nums[:]) #传的是nums contents复制,即nums改变,a不会随之改变
nums[0], nums[1] = nums[1], nums[0] #a=[3,6,2]
#test2
b=[]
b.append(nums) #传的是nums引用,即nums改变,b也随之改变  b=[3,6,2]
nums[0], nums[1] = nums[1], nums[0] #b=[6, 3, 2]

输入一个字符串序列,长度不超过9(可能有字符重复),字符只包括大小写字母。

#simple解法
class Solution:
    def Permutation(self, ss):
        if len(ss) <= 1:
            return ss
        res = set()
        # 遍历字符串,固定第一个元素,第一个元素可以取a,b,c...,然后递归求解
        for i in range(len(ss)):
            for j in self.Permutation(ss[:i] + ss[i+1:]): # 依次固定了元素,其他的全排列(递归求解)
                res.add(ss[i] + j) # 集合添加元素的方法add(),集合添加去重(若存在重复字符,排列后会存在相同,如baa,baa)
        return sorted(res)         # sorted()能对可迭代对象进行排序,结果返回一个新的list
#复杂解法
#ss(str)-->【分】先变成list-->【合】变回str
def Permutation(self, ss):
    def dfs(first):  # first 记录每次开始的第一个位置
        if first == n:  # 当起始位置超越数组长度了,停止,加入结果集
            res.add(''.join(ss))
        for i in range(first, n):  # 第一个数字与后面所有数字依次交换
            ss[first], ss[i] = ss[i], ss[first]
            dfs(first + 1)  # 递归替换下一个位置
            ss[first], ss[i] = ss[i], ss[first]  # 回溯,还原,才能进行下一次交换!

    if not ss: return []
    n = len(ss)
    res = set()
    ss = list(ss) 
    dfs(0)
    return sorted(res) # sorted()能对可迭代对象进行排序,结果返回一个新的list
#知识点
ss='abc'
ss = list(ss)
''.join(ss)
Out[37]: 'abc'
ss
Out[38]: ['a', 'b', 'c']
''.join(ss)
Out[39]: 'abc'
组合

38.2 字符串的所有组合
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
返回的结果包括空列表。
leecode78

dp[i] = dp[i-1] + [each+[nums[i]] for each in dp[i-1]]
解法一:动态规划

def subsets_1(self, nums: List[int]) -> List[List[int]]:
    res = [[]]
    for x in nums:
        res += [ each+[x] for each in res]
    return res

解法二:回溯,递归
依次加入,走到底了就回溯。
input: [1, 2, 3]
[out]: 1, 12, 123, 13, 2, 23, 3

def subsets_2(self, nums: List[int]) -> List[List[int]]:
    def dfs(first):  # first 指向当前第一个元素
        res.append(sub[:])  # 复制并加入结果集
        if first == len(nums):  # 若first走完了数组,返回
            return
        # 这里与全排列相比,不用交换数字,即数组的顺序是固定的。只需要依次加入元素就可以。
        for i in range(first, len(nums)):  # 从当前位置到末尾依次遍历
            sub.append(nums[i])  # 加入当前元素
            dfs(i + 1)  #【!!与排列区别】(防止重复)#  # 从下一个位置开始递归
            sub.pop()  # 回溯,去除sub中的元素,为了下一次遍历

    res = []
    sub = []  # 中间量,因组合,长度一直在change
    n = len(nums)
    dfs(0)
    return res

Tips: list类型 可以object.pop()

位运算
共有n个字符,对应n位bit,总共有2**n种排列,哪一位为1则将对应位置的字符加入到子集中

#法一
def subsets_3(self, nums: List[int]) -> List[List[int]]:
    n=len(nums)
    res=[]
    for i in range(2**n,2**(n+1)):  #保持二进制是n长度 2**n是(n+1)长度 bin(2**2)=>100
        bit = bin(i)[3:]
        res.append( [nums[j] for j in range(len(bit)) if bit[j] =='1'])
    return res
    
#法二
def subsets(self, nums: List[int]) -> List[List[int]]:
    if not nums: return []
    res = []
    for i in range(2 ** len(nums)):  #e.g:n=3 0~7
        sub = []
        for j in range(len(nums)):   #0~2
            if i >> j & 1:
                sub.append(nums[j])
        res.append(sub)
    return res
知识点
bin(x)   x -- int 或者 long int 数字
>>>bin(521)
#这里的显示结果形式与我们平时习惯有些差别,主要是前面多了0b,这是表示二进制的意思。
'0b1000001001'
res.append([nums[j] for j in range(len(bit)) if bit[j] == '1'])
等价于
sub=[]
for j in range(n):
    if bit[j]=='1':
        sub.append(nums[j])
res.append(sub)
排列(实际problem):

n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
leecode 51
在这里插入图片描述
我们如果把 queens, xy_dif, xy_sum 三个状态的变化全部放入递归函数的变量中,则不需要我们手动回溯了,递归时会自动还原上一次的变量。

解法一:
回溯步骤:
: 从第一行第一列开始遍历。循环列并且试图在每个 column 中放置皇后
: 停止条件:若棋子数目等于n,满足要求加入结果。
: 若满足要求则放置棋子。
: 回溯,拿掉棋子,恢复状态。

#简洁版
"""dfs,把需要回溯的状态放入递归函数的变量可自动回溯。
"""
def solveNQueens_2(self, n):
    def dfs(queens, xy_dif, xy_sum):
        row=len(queens)
        if len(queens)==n:
            result.append(queens)
            return
        for col in range(n):   #相当于广度优先搜索,故可找出all sol
            if not( col in queens or row-col in xy_dif or row+col in xy_sum ): #摩尔根定律:非(并)=(非交)#row-col不能加abs
                dfs(queens+[col], xy_dif+[row-col], xy_sum+[row+col])

    result=[]
    dfs([],[],[])
    return [["."*i + "Q"+"."*(n-i-1)  for i in sol]   for sol in result]
#Tip:
sol=[1, 3, 0, 2]
a=[x for x in sol]
等价于
a=[]
for x in sol:
    a.append(x)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值