昨天看到有人在TL里说一个面试题 : 不用递归法 求一个固定集合内的所有子集。经 @miloyip 指出,这是个power set 的问题,在中文中称为幂集。这个中学数学里就学过了,不过如何用计算机求幂集还真没考虑过,就索性找了找求幂集的算法。根据wiki上的介绍和我自己的理解( http://en.wikipedia.org/wiki/Power_set),给定一个包含n个元素的集合s,我用python实现了三种计算幂集的算法。如果没有额外说明,下文中的 union表示取两个集合的合集。

1. 利用二进制数与幂集之间的对应关系

在[0,2^(n-1)]的整数区间上任取一个值x,x的二进制表示可以用来表示s的一个子集:对于x的第i位,如果为1,则此子集包含s的第i个元素,否则不包含。因此,只要遍历 [0,2^(n-1)]的整数区间,就能列举出s的所有子集,这些子集的集合就是s的幂集。这个方法陈硕老大也指出来了。代码如下:

def power_set(s):

n = len(s)

test_marks = [ 1<

for k in range(0, 2**n):

l = []

for idx, item in enumerate(test_marks):

if k&item:

l.append(s[idx])

yield set(l)

#A simple test

def __test__():

s = [1,2,3,4]

for e in power_set(s):

print e

__test__()

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

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

#simply add a set s to list l, with duplicate check

def add_set_to_list(l, s):

if s not in l:

l.append(s)

#F(e, T) = {x union {e} | x belongs to T}

def F(e, T):

l = []

add_set_to_list(l, e)

for x in T:

y = e | x

add_set_to_list(l, y)

return l

def power_set(s):

l = []

if not s: #empty set

l.append(set())

return l

for e in s:

es = set((e,))

t = s - es

s2 = power_set(t)

for i in s2:

add_set_to_list(l, i)

for i in F(es, s2):

add_set_to_list(l, i)

return l

上面这个算法有两个缺点:一是计算过程中会重复生成某些集合,因此 有重复计算,二是它是递归的,效率上可能不高。经过与 @GiantIron 讨论,得到了一种非递归算法,思想跟上面的递归算法类似,但又有区别,而代码要简单得多。非递归算法的数学描述如下:

给定一个集合s,它的幂集表示为P(s), 则对于一个元素e, P( s union {e} } = P(s) union F(e, P(s))。直观地说,已知集合s和它的幂集P(s),如果往s中加入一个新元素e,则形成的新的集合的幂集是 P(s) 和 F(e, P(s)) 的合集。其中F()函数在递归算法的实现中已经给出。上述描述其实跟递归算法中类似,但是我们可以利用这个关系来增量地计算,而不用递归。

代码如下,l用来保存增量计算出来的幂集,由于后续计算依赖于之前计算的结果,这里也没有用yield,直接返回一个list。因为这个计算过程中不会出现重复的子集,所以直接用list.extend()代替了取合集(union)的操作。同样,在递归算法中的F()函数的实现中有检查是否是重复元素的操作,而在这里其实是不必要的:

def power_set(s):

l = [set(),]

for e in s:

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

return l

3.  s的幂集 = { subsets(s, k) |  k=0, 1, 2, ..., n}

其中subsets(s,k)表示s所有模为k的子集,即 包含k个元素。这个关系是显而易见的。因此只要求出subsets(s,k),幂集也就很容易了。求subset(s,k)的代码我没有自己写,在这里 有一个实现,也是递归的,它利用了幂集与二项式系数之间的关系以及帕斯卡法则 (其实跟杨辉三角所描述的关系是一样的),显得很优美。代码如下,其中k_subsets(s,k)是别人实现的subsets(s,k)的函数。

def power_set(s):

for k in range(0, len(s)+1):

for k_set in k_subsets(s,k):

yield k_set

除此了上述方法外,陈硕老大也介绍了用stl的next_permutaion()来生成组合数(链接 ),进而求幂集。我觉得这个方法跟上述第三种方法有相似的地方,都是利用了组合与幂集之间的关系,不过生成组合的方法不一样。我相信还有更多的方法可以解决这个问题。

解决同一个问题可以有很多种方法,而看似简单的一个问题,真正要正确地解出来也不是那么容易。由于python本身提供了对set的支持,实现幂集也轻松了很多。不过set对象本身不能作为set的元素,这一点有待推敲,我对python也不是太熟悉。

python求幂集_求幂集的算法 - Sethylar的个人页面 - OSCHINA - 中文开源技术交流社区...相关推荐

  1. python倒排索引实现_倒排索引原理和实现 - uncle_LLD的个人空间 - OSCHINA - 中文开源技术交流社区...

    关于倒排索引 搜索引擎通常检索的场景是:给定几个关键词,找出包含关键词的文档.怎么快速找到包含某个关键词的文档就成为搜索的关键.这里我们借助单词--文档矩阵模型,通过这个模型我们可以很方便知道某篇文档 ...

  2. java如何测试定时器_如何测试定时任务 - 邓竣的个人页面 - OSCHINA - 中文开源技术交流社区...

    系统一般会有一些后台定时任务,假设我们使用quartz实现定时任务,那么有两个测试功能点: 定时任务逻辑是否正确 定时器cron表达式编写是否正确,触发时间点是否正确 定时任务逻辑测试 如果定时任务在 ...

  3. java实现近邻聚类算法,近邻传播聚类算法 - osc_t74tdxrl的个人空间 - OSCHINA - 中文开源技术交流社区...

    近邻传播聚类算法 1.算法简介 AP(Affinity Propagation)通常被翻译为近邻传播算法或者仿射传播算法,是在2007年的Science杂志上提出的一种新的聚类算法.AP算法的基本思想 ...

  4. 人工鱼群算法python代码_人工鱼群算法python_鱼群算法 - Brillou的个人空间 - OSCHINA - 中文开源技术交流社区......

    本算法是参照李晓磊博士的论文实现的,详细的算法原理可阅读<一种新型的智能优化方法_人工鱼群算法_李晓磊> 算法基于鱼群的生存行为:在一片水域中,鱼存在的数目最多的地方就是本水域中富含营养物 ...

  5. python 过采样 权重实现_不平衡数据集的处理 - osc_sqq5osi1的个人空间 - OSCHINA - 中文开源技术交流社区...

    一.不平衡数据集的定义 所谓的不平衡数据集指的是数据集各个类别的样本量极不均衡.以二分类问题为例,假设正类的样本数量远大于负类的样本数量,通常情况下通常情况下把多数类样本的比例接近100:1这种情况下 ...

  6. java 投票算法_摩尔投票算法 - woshixin的个人空间 - OSCHINA - 中文开源技术交流社区...

    摩尔投票算法(Moore majority vote algorithm) 这个在wiki的介绍在https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_m ...

  7. python 千位分隔符_玩转千位分隔符输出 - leejun2005的个人页面 - OSCHINA - 中文开源技术交流社区...

    1.Python 1.1 format方法: 2.7版本以上直接用format设置千分位分隔符 Python 2.7 (r27:82500, Nov 23 2010, 18:07:12) [GCC 4 ...

  8. python编程代码执行漏洞_代码执行漏洞 - 安全先师的个人空间 - OSCHINA - 中文开源技术交流社区...

    0x00 前言 最近发现的一个新站,不妨试试手. 0x01 基础信息 漏洞点:tp5 method 代码执行,payload如下 POST /?s=captcha_method=__construct ...

  9. python读写磁盘扇区数据有什么用_磁盘存放数据原理 - osc_v8xs2czi的个人空间 - OSCHINA - 中文开源技术交流社区...

    磁盘结构作用数据原理 拓扑图 盘面(side) 模型: 1.磁盘圆形盘面,一个磁盘内含有多个盘面. 2.层叠关系,每个盘面之间不会贴着. 3.第一个盘的正面成为0面,反面为1面:第二个盘正面为2面,反 ...

  10. python编程题说句心里话_说句心里话 A - osc_6kxooi0n的个人空间 - OSCHINA - 中文开源技术交流社区...

    说句心里话 A ‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬ ...

最新文章

  1. DES对称加密(2)三重DES
  2. ssm整合之七 事务以及404页面处理
  3. 【编程题目】复杂链表的复制☆
  4. 13个mysql数据库的实用SQL小技巧
  5. mPaas 运维流程介绍
  6. SQL Server类型与C#类型对应关系
  7. Linux——批量查找替换方法(VIM和sed)
  8. centos8 配置 dns_如何在Ubuntu 18.04上设置DNS名称服务器 | linux资讯
  9. 为何要搞 10 年?方舟编译器专家首次回应
  10. [湖南集训] 谈笑风生
  11. eslint 快捷键设置_eslint的妙用和快捷修复
  12. B站排行榜(简陋版)
  13. Java如何处理参数中带特殊符号的请求?
  14. 小试ESP8266(一) 一只电阻, 几条语句, 摆脱深度睡眠反复重启的困扰
  15. 电脑按键坏掉之后的解决办法
  16. Java登录界面的实现(注册、登录、背景图片)
  17. c语言题查询答案,C语言习题级答案.docx
  18. php 网页合成图片,PHP怎么把网页内容原封不动的给生成图片
  19. 关于空间拓扑(lynn的自语)
  20. 物联网开发笔记(27)- 使用Micropython开发ESP32开发板之控制240x240的oled屏幕(ST7789芯片)

热门文章

  1. 基于HyperVID数据集训练自己的车型识别系统
  2. 使用FFmpeg工具进行推流、拉流、截图、变速、转换,及常见问题处理
  3. python scipy实例_python简单实现最大似然估计scipy库的使用详解
  4. 医院管理系统/医院药品管理系统
  5. webrtc系列3——对于stun和turn的理解
  6. python阈值分割_Python实现otsu阈值分割算法
  7. 松下PLC REXT总线伺服案例 本案例采用松下FPXH系列的总线型 PLC和松下总线伺服共8轴的系统
  8. iOS 开发经验 - 转载
  9. 互联网行业概括,让我们熟悉和了解未来的工作环境
  10. SAP B1打印报表实现本页合计和本单合计的方法