给定字符串或列表,求字典排序的问题

目录

0.简介

1.无重复数字的排列

2.有重复数字的排列

3.第k个排列


0.简介

最近参加了网易校招的提前批笔试,其中有一题是关于字典排序问题:

问题说明:

假设给定m个'a'和n个'z',求按照字典排序生成的第k个字符串(字符串长度为m+n,无重复序列)

本人以前在LeetCode上刷了大约100道题,其中也遇到了一些关于字典排序的问题,不过上面这个题实在是不会做,如果有哪位大神知道解,还请不吝赐教。

本博文整理了我在LeetCode上遇到的字典排序(即排列)问题,题目链接如下,本文所给出的解法参考了LeetCode上大神的答案,本文所有代码均为python3:

1.无重复数字的排列:Permutations

2.有重复数字的排列:Permutations II

3.第k个排列:Permutation Sequence

1.无重复数字的排列

问题说明:

给定一组不同的整数,返回所有可能的排列。

例如:

Input: [1,2,3]
Output:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

方法一:

采用深度优先搜索,比较好理解,每次按顺序从剩余序列中选择一个数插入到path中,直到访问完所有点。

class Solution:
    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = []
        def dfs(A, path, res):
            if not A:
                res.append(path)
            for i in range(len(A)):
                dfs(A[:i]+A[i+1:], path+[A[i]], res)
        
        dfs(nums, [], res)
        return res

方法二:

这是LeetCode上一位非常非常牛逼的人的答案,很多题目下都有这位StefanPochmann大神完美解答,有兴趣可以去围观。

这个方法其实和方法一的思路是一样的,在此列出来是因为本人很羡慕这种一句话解决的代码。

class Solution:
    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        return [[n]+p
               for i, n in enumerate(nums)
               for p in self.permute(nums[:i]+nums[i+1:])] or [[]]

2.有重复数字的排列

问题说明:

给定可能包含重复项的数字集合,返回所有可能的唯一排列。

例如:

Input: [1,1,2]
Output:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]

思路:

采用插入法:

第一步,把第一个数插入到空列表[]中,res = [[1]];

第二步,此时的num还是1,这是ans = [1],虽然有前后两个位置可以插入,但是为了排除重复,只往相同数字的前方各位置插入,此时的res = [[1, 1]];

第三步,此时的num为2,ans = [1, 1],此时ans中没有等于2的数字,因此2就可以插入到ans的len(ans)+1个位置,分别产生[2,1,1],[1,2,1],[1,1,2];

到此所有数字处理完毕,res = [[2,1,1], [1,2,1], [1,1,2]],由于结果需要按字典序列输出,那么排序以下就好了。

class Solution:
    def permuteUnique(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        # 插入法
        res = [[]]
        for num in nums:
            new_res = []
            for ans in res:
                # 长度为len(ans)的序列有len(ans)+1个插入点
                for i in range(len(ans)+1):
                    new_res.append(l[:i]+[num]+l[i:])
                    # 遇到相同的数,只往前插,不往后插
                    if i<len(l) and l[i]==num: 
                        break              #handles duplication
            res = new_res
        return list(sorted(res))      

3.第k个排列

问题说明:

集合[1,2,3,...,n]总共包含n!独特的排列。

通过按顺序列出和标记所有排列,我们得到n = 3的以下序列:

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"

给定n和k,返回第k个排列序列。

注意:

给定n将介于1和9之间。
给定k将介于1和n!之间。

Example 1:

Input: n = 3, k = 3
Output: "213"

Example 2:

Input: n = 4, k = 9
Output: "2314"

 思路:

对于n的排列,第一个(n-1)! 排列从1开始,下一个(n-1)! 从2开始,......等等。 并且在每组(n-1)中! 排列,第一个(n-2)! 排列从最小的剩余数字开始,......

因此,我们可以使用循环来检查序列号落入的区域并获得起始数字。 然后我们调整序列号并继续。

class Solution:
    def getPermutation(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: str
        """
        import math
        
        ans = ""
        a = list(range(1, n+1))
        k -= 1  # 消除index==0的影响
        while n > 0:
            n -= 1
            # 获取序号
            index, k = divmod(k, math.factorial(n))
            ans += str(a[index])
            # 删除使用过的数字
            a.remove(a[index])
        return ans

目前遇到的关于排列的问题就是上面这些,如果以后有遇到会更新本文。

--by 2018/8/22

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值