算法21--全排列,去重全排列以及非递归实现

问题1: 给定字符串1234无重复字符,求其所有排列

递归方式求解:

def swap(num, i, j):
    tmp = num[i]
    num[i] = num[j]
    num[j] = tmp
 
#num无重复数字 
def fullSort(num, index):
    if index==len(num)-1:
        print (num)
        return
    for i in range(index, len(num)):
        swap(num, index, i)
        fullSort(num, index+1)
        swap(num, index, i)

以1234为例,首先考虑第一位的可能,有1,2,3,4四种可能,当第一位固定时,例如为1,后面三位又是一个递归问题,用变量index来标识当递归到数组的第几位

当index==len(num)-1时,说明所有数字已经交换完毕,则输出数组即可,此时为一种排列。

当index<len(num)-1时,说明例如index=0,说明当前正在考虑第index位的取值,可以把index+1一直到len(num)-1所有数字都置换到num[index]中,然后依次求解每个递归问题

在每一次递归循环中,数组的位置索引信息    0----index----i------len-1

index表示数组的位置索引,index取值0----len-1

当index确定某一值时,该位置的取值方式可以为i=index--len-1,依次将后面数字i交换到该位置index,递归求解子问题

当index==len-1,说明所有可能交换情况已经完成,可以输出该数组,即为一种排列方式

问题2:给定字符串12234,求其所有排列字符串要去重

数组索引:

0---index---i----len-1

考虑将num[index]与num[i]交换,若在index--i-1中已经存在num[i],则num[i]不应该与num[index]交换,因为交换依次为按顺序交换,i取值从index一直到i,若这中间出现过num[i],说明num[index]已经被交换过,若再次交换便会出现重复。

例如 num = [1 2 2 3 4] :

index=1   i的变化范围从1---4,当i=2时,此时num[i]=2,而在index=0---i-1=1之间num[1]=2,说明num[1]已经出现在num[0]位置上,若num[2]再次与num[0]交换,则会出现重复排列。

因此在每次将num[i]与num[index]交换时,需要考虑 num[i]在num[index:i]中是否出现过:

def isSwap(num, index, i):
    for j in range(index, i):
        if num[j]==num[i]:
            return False
    return True

去重的排列方式如下:

#num中有重复数字      
def fullSort2(num, index):
    if index==len(num)-1:
        print (num)
        return
    for i in range(index, len(num)):
        #print (isSwap(num, index, i))
        if isSwap(num, index, i):
            swap(num, index, i)
            fullSort2(num, index+1)
            swap(num, index, i)

问题3:给定字符串1234,求其所有排列,使用非递归方式

非递归解法:

给定一个数字字符串,将其看成一个整数,若每次都寻找一个比它刚好更大的数输出,继续寻找比上一个更大的数字,这样依次输出,则可以输出所有组合,并且不会重复。

寻找一个比某数刚好更大的方法:

给定数字字符串数组,从后往前寻找,寻找一个相邻递增的两个数,则前一个数称为替换数,其索引称为替换点;然后从替换点之后开始寻找一个比替换数大的最小数,称为被替换数;交换替换数以及被替换数;将替换点之后的所有数字翻转;输出该数字即时目标值。

例如: num=[5,4,7,8,2,0]  从后往前寻找相邻递增的两个数为7,8,则替换数为7  替换点为index=2 从替换点往后寻找比替换数大的最小值,即被替换数为8,交换7,8   得548720,把替换点之后的数字给翻转  得到548027  。即比547820大的第一个数为548027

输出一个数组,首先进行排序获取到最小值,然后依次执行上述过程,逐次增大该数,一直到最大值结束即可。

#寻找比替换点大的最小数,倒序寻找,第一个大的数就是目标值 
def findBiggerThanReplaceNum(num, r):
    min = r
    for i in range(len(num)-1, r, -1):
        if num[i]>num[r]:
            return i
    return min
    
def reverse(num, i, j):
    while i<j:
        swap(num, i, j)
        i += 1
        j -= 1
        
def fullSort3(num):
    num.sort()
    print (num)
    #替换数的下标 排序完成后第一个数
    r = len(num)-1
    #替换点的下一个数坐标
    m = r
    while r>0:
        m = r    
        r -= 1
        #print ('r = ', r)
        if num[r]<num[m]:
            s = findBiggerThanReplaceNum(num, r)
            #print ('s = ',s)
            swap(num, r, s)
            reverse(num, r+1, len(num)-1)
            print (num)
            #break
            r = len(num)-1

首先排序数组

r表示循环寻找替换点变量  m表示为r下一个索引

若num[r]<num[m]则说明r为替换点,找到替换点之后比替换数大的最小值被替换数s,从后往前第一个比替换数大的数即为被替换数

交换替换数以及被替换数

翻转替换数之后的所有字符

r指向数组末尾len-1,继续循环

当数组已经完全降序输出时,r从len-1一直到0,当r=0,m=1此时num[r]<num[m]仍不满足,则退出循环,结束遍历。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值