python中的幂函数,python幂运算函数

  python中的幂函数,python幂运算函数

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

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

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

  defpower_set:

  n=透镜

  测试标记=[1

  forkinrange(0,2**n):

  l=[]

  foridx,iteminenumerate(test_marks):

  ifkitem:

  附加(s[idx])

  屈服集

  #Asimpletest

  def__test__():

  s=[1,2,3,4]

  foreinpower_set:

  打印机

  __测试_ _()

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

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

  #simplyaddasetstolistl,withduplicatecheck

  defadd_set_to_list(l,s):

  ifsnotinl:

  l .追加

  #F(e,T)={xunion{e}xbelongstoT}

  defF(e,T):

  l=[]

  添加集合到列表(l,e)

  forxinT:

  y=ex

  add_set_to_list(l,y)

  returnl

  defpower_set:

  l=[]

  ifnots:#emptyset

  l.append(set())

  returnl

  外来者:

  es=set((e,))

  t=s-es

  s2=功率设置(t)

  foriins2:

  add_set_to_list(l,I)

  foriinF(es,s2):

  add_set_to_list(l,I)

  returnl

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

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

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

  defpower_set:

  l=[set(),]

  外来物:

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

  returnl

  3.s={subsets(s,k) k=0,1,2,n}

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

  defpower_set:

  forkinrange(0,len(s) 1):

  fork_setink_subsets(s,k):

  yieldk_set

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

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

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: