leetcode 46. Permutations and leetcode 47. Permutations II(python实现)

一:leetcode 46. Permutations

1:题意

给定一个数组,数组内所有元素是唯一的,返回这些数的排列组合

2:输入输出

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

3:分析

如样例所示:输入[1,2,3]时,构造的状态树如下所示:
在这里插入图片描述
回溯法:当使用1,余下只能使用2,3排列,选择2只能选择3,得到一种全排列1,2,3. 此时状态回退,选择3只能选择2,得到一种全排列1,3,2。

从上图来看,回溯的意思就是,当深度优先搜索到叶子节点时,此时保存这一条路径就是一个排列,然后沿着叶子节点向根节点回溯,再沿着没有访问过的节点深度优先搜索到其他叶子节点,又是另外一个排列了

4:python代码实现

回溯+hash来实现:

		if not nums: return [[]]
        self.res = []
        vis = set() # 避免重复访问
        
        def traceback(path, nums, vis):
            if len(path) == len(nums): # 到达叶子节点了
                self.res.append(path[:])
                return  # 不用写else了
            for n in nums:  # 把数组中的元素都遍历一次。每个元素都当一次根节点
                if n in vis: continue
                path.append(n)
                vis.add(n)
                traceback(path, nums, vis) # 一直走到叶子节点
                path.pop()  # 把一条路径的最后节点去掉,往根节点回溯
                vis.remove(n)
        
        traceback([], nums, vis)
        return self.res

插值法实现

	def permute(self, nums):
	# 方法一:插入法,16ms,11.9MB 还不错
        res = [[]]
        if not nums: return res
        for num in nums:  # 单数表示一个数,复数表示数组
            perm = []  # 存中间结果,如 [[1,2],[2,1]]
            for line in res:  # 取出一行出来
                L = len(line)+1 # 加1是因为空数组的时候需要初始化
                for i in xrange(L):
                    perm.append(line[:i] + [num] + line[i:]) # insert num
            # print(perm)
            res = perm  # 指向同一个
        
        return res

二:leetcode 47. Permutations II

1:题意

给定一个数组,数组内所有元素有重复,返回这些数的排列组合,答案没有重复值!

2:输入输出

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

3:分析

如样例所示:输入[1,1,2]时,遍历的状态如下图所示:
在这里插入图片描述
如上图所示:输入[1,1,2],
当访问第一个值1时,接下来可以访问第二个值1,最后访问第三个值2。
当访问第二个值1时,此时1已经当过根节点了,所以要及时剪枝,直接返回
当访问第三个值2时,依次访问1,1是可以的,但是再次访问1时也要及时剪枝,已经访问过了,不再重复访问。

4:python代码实现

回溯法来实现,并通过vis数组来记录每一个值是否访问过:

if not nums: return [[]]
        self.res = []
        nums.sort()  # 保证相同数字会相邻
        vis = [False] * len(nums)
        
        def traceback(line, vis, nums):
            if len(line) == len(nums): # 到了叶子节点了
                self.res.append(line[:]) # 得用切片来复制数组
                return  # 不用写else了
            for i in range(len(nums)):  
                if vis[i]: continue    # nums[i]已经访问过了,剪枝(上图中第一个红色叉)
                # nums[i]没访问过,并且nums[i]与nums[i-1]相同也需要剪枝(上图中第二个红色叉)
                if i>0 and nums[i] == nums[i-1] and not vis[i-1]: continue 
                line.append(nums[i])
                vis[i] = True
                traceback(line, vis, nums)
                line.pop()  # 去掉一条路径中的最后一个来回溯到前一个状态
                vis[i] = False
        
        traceback([], vis, nums)
        return self.res

三:字符串的排列(剑指offer)

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
此外,输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

# -*- coding:utf-8 -*-
class Solution:
    def Permutation(self, ss):
        # write code here
        # 回溯法
        if not ss: return []
        self.res = []
        string = list(ss)  # [s for s in ss] str->array
        string.sort()  # 字符排序,让重复字符都在一起
        
        vis = [False] * len(string)
        
        def traceback(path, string, vis):
            if len(path) == len(string):
                self.res.append(''.join(path))
                return
            for i in range(len(string)):
                if vis[i]: continue
                if i > 0 and string[i] == string[i-1] and vis[i-1] == False: continue # 条件都不能少,不然通不过
                path.append(string[i])
                vis[i] = True
                traceback(path, string, vis)
                path.pop()
                vis[i] = False
        
        traceback([], string, vis)
        return self.res     

31. Next Permutation

在一个排列按照字母表顺序的情况下,找到下一个更大的排列是多少。如果已经是最大的,那么应该翻转。必须原地翻转。

class Solution(object):
    def nextPermutation(self, nums):
        n = len(nums) - 1
        i = n
        
        while i > 0 and nums[i] <= nums[i-1]: # 逆序遍历,递增序列
            i -= 1
        # i-1才是我所需要的数
        if i > 0:
            # 逆序找第一个比nums[i-1]大的数
            j = n
            while j >= 0 and nums[j] <= nums[i-1]:
                j -= 1
            
            nums[i-1], nums[j] = nums[j], nums[i-1]  # 交换
        
        # 从i到结尾都得逆序
        self.reverse(nums, i)
    
    def reverse(self, nums, start):
        i, j = start, len(nums)-1
        while i < j:
            nums[i], nums[j] = nums[j], nums[i]
            i += 1
            j -= 1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值