[Alg]-字符串的排列

交换法

字典序法

 

字符串全排列:输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

交换法

把字符串分成两部分:第一个字符,和剩余的字符串。因此求字符串的排列,就可以:

  • 可以出现在第一个字符位置的字符:把第一个字符和字符串中剩余的所有字符交换;
  • 固定第一个字符,递归求剩余字符串的排列。
def getAllRankRecursion(lstOri:list)->set:
    result = set()
    if not lstOri:
        return result

    def addResult(rank):
        get = ''.join(rank)
        result.add(get)
        print(get)

    def needSwap(rank, start, end)->bool:
        for i in range(start,end):
            if rank[i] == rank[end]:
                return False
        return True


    def helper(rank:list, start:int):
        if start==len(rank)-1:
            addResult(rank)
            return       

        helper(rank, start+1)
        for i in range(start+1, len(rank)):
            if(needSwap(rank, start, i)):
                rank[i], rank[start] = rank[start], rank[i]
                helper(rank, start+1)

                rank[i], rank[start] = rank[start], rank[i]

    helper(lstOri, 0)
    return result

注意:在字符串中有重复字符时,需要确定是否需要交换。若字符在前面字符串中已出现过,则不需要交换;即第i个数与第j个数交换时,要求[i,j)中没有与第j个数相等的数。

字典序法

先对字符串排序(从小到大),然后查找其下一个排列(如"1234"的下一个排列就是"1243"),依次反复查找,即得到了全排列。如何查找下一个排列(以926520为例):

  • 从后向前查找第一对相邻的递增数:即26;
  • 查找到的一对字符中,前面的字符即为替换数(对应位置即为交换点a):即2;
  • 从后面查找比替换数大的最小的数:即5;
  • 交换2与5(即956220),然后将交换点后面的字符串反序(即950226)。
def getAllRankWhile(rank:list)->set:
    def nextPermutation(rank:list)->bool:
        for i in range(len(rank)-1, 0, -1):
            if rank[i-1]<rank[i]:  # get the first Non-increase seq
                changed = i-1
                least = i
                for j in range(i+1, len(rank)):
                    if rank[changed]<rank[j] and rank[least]>=rank[j]:
                        least = j

                # change the elements, and reverse
                rank[changed], rank[least] = rank[least], rank[changed]
                rank[i:] = rank[:i-1:-1]
                return True

        return False

    result = set()
    rank.sort()
    while True:
        get = ''.join(rank)
        print(get)
        result.add(get)

        if not nextPermutation(rank):
            break;

    return result
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值