python幂运算函数

昨天看到有人在TL里说了一个面试问题:不用递归找到一个固定集合中的所有子集。按照@miloyip的说法,这是一个幂集的问题,中文叫幂集。这次中学数学学的,但是真的没想过怎么用计算机求幂集,就干脆找算法求幂集。根据维基上的介绍和我自己的理解(http://en . Wikipedia . org/wiki/Power _ set),给定一个包含n个元素的集合S,我用python实现了三种计算幂集的算法。除非另有说明,下面的并集是指取两个集合的并集。

  1.利用二进制数和幂集的对应关系。

  取[02 (n-1)]整数区间内的任意值xx的二进制表示可以用来表示s的一个子集:对于x的第I位,如果为1,则这个子集包含s的第I个元素,否则不包含。所以只要遍历[02 (n-1)]的整数区间,就可以列出S的所有子集,这些子集的集合就是S的幂集,银耳汤的自信老板也指出了这个方法。代码如下:

  defpower_set:

  n=透镜

  测试标记=[1

  forkinrange(02**n):

  l=[]

  foridxiteminenumerate(test_marks):

  ifkitem:

  附加(s[idx])

  屈服集

  #Asimpletest

  def__test__():

  s=[1234]

  foreinpower_set:

  打印机

  __测试_ _()

  2.递归计算和一种改进的非递归算法。

  在wiki上给出了递归算法。总的思路是先取出S中的一个元素E,然后求出S中其他元素组成的集合的幂集,再将E与求出的幂集的每个组合进行组合,求出结果集。因此,可以列出所有可能的子集。这个算法的某些子集在枚举时可能会重复出现,所以我没有用yield,而是直接返回了一个list。代码如下:

  #simplyaddasetstolistlwithduplicatecheck

  defadd_set_to_list(ls):

  ifsnotinl:

  l .追加

  #F(eT)={xunion{e}xbelongstoT}

  defF(eT):

  l=[]

  添加集合到列表(le)

  forxinT:

  y=ex

  add_set_to_list(ly)

  returnl

  defpower_set:

  l=[]

  ifnots:#emptyset

  l.append(set())

  returnl

  外来者:

  es=set((e))

  t=s-es

  s2=功率设置(t)

  foriins2:

  add_set_to_list(lI)

  foriinF(ess2):

  add_set_to_list(lI)

  returnl

  上述算法有两个缺点:一是在计算过程中会重复生成一些集合,因此存在重复计算;二是递归,效率可能不高。和@GiantIron讨论后得出一个非递归算法。思路和上面的递归算法类似,但有区别,代码简单很多。非递归算法的数学描述如下:

  给定一个集合s,其幂集表示为p (s),那么对于一个元素ep (s{e}}=p (s)f (eP(s))。直观地说,给定集合S及其幂集P(s),如果给S增加一个新元素E,则形成的新集合的幂集是P(s)F(eP(s))的并集。f()函数已经在递归算法的实现中给出。上面的描述其实和递归算法差不多,但是我们可以用这个关系来增量计算,而不是递归。

  代码如下。l用于保存按增量计算的功率集。由于后面的计算依赖于前面计算的结果,所以这里不使用yield,直接返回一个列表。因为这个计算过程中不会出现重复的子集,所以union的运算直接被list.extend()代替。同样,在递归算法中f()函数的实现中,有一个检查是否是重复元素的操作,但在这里其实是不必要的:

  defpower_set:

  l=[set()]

  外来物:

  l.extend(F(set((e)l))

  returnl

  3.s={subsets(sk) k=012n}

  其中subsets(sk)表示s的所有模都是k的子集,即它包含k个元素。这种关系显而易见。因此,很容易找到子集(sk)。寻找子集(sk)的代码不是我自己写的。下面是一个实现,也是递归的。它利用了幂集与二项式系数的关系和帕斯卡法则(其实和杨辉三角形描述的关系是一样的),看起来非常漂亮。代码如下,其中k_subsets(sk)是其他人实现的子集(sk)的函数。

  defpower_set:

  forkinrange(0len(s) 1):

  fork_setink_subsets(sk):

  yieldk_set

  除了以上方法,信心满满的银耳汤老板还介绍了使用stlnext _ permutaion()生成组合数(链接)然后求幂集。我觉得这种方法和上面提到的第三种方法类似,都是利用了组合和幂集的关系,只是生成组合的方法不同。我相信有更多的方法可以解决这个问题。

  解决同一个问题的方法有很多种,但要正确解决一个看似简单的问题,却不是那么容易。因为python本身提供了对set的支持,所以实现幂集要容易得多。但是set对象本身不能作为集合的元素,这是需要考虑的,而且我对python也不熟悉。

本文来自网络,不代表菜鸟教程之家立场,转载请注明出处。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值