二进制全排列 java_排列组合算法真厉害,傻瓜都能学会

作者:枕边书来源:https://zhenbianshu.github.io/2019/01/charming_alg_permutation_and_combination.html

需求

最近工作中碰到一个需求:我们的数据表有多个维度,任意多个维度组合后进行 group by 可能会产生一些”奇妙”的反应,由于不确定怎么组合,就需要将所有的组合都列出来进行尝试。

抽象一下就是从一个集合中取出任意元素,形成唯一的组合。如 [a,b,c] 可组合为 [a]、[b]、[c]、[ab]、[bc]、[ac]、[abc]。

要求如下:

  • 组合内的元素数大于 0 小于等于 数组大小;
  • 组合内不能有重复元素,如 [aab] 是不符合要求的组合;
  • 组合内元素的位置随意,即 [ab] 和 [ba] 视为同一种组合;

看到这里,就应该想到高中所学习的排列组合了,同样是从集合中取出元素形成一个另一个集合,如果集合内元素位置随意,就是组合,从 b 个元素中取 a 个元素的组合有 种。而如果要求元素顺序不同也视为不同集合的话,就是排列,从 m 个元素取 n 个元素的排列有 种。

我遇到的这个需求就是典型的组合,用公式来表示就是从元素个数为 n 的集合中列出 种组合。

文中算法用Java实现。

从排列到组合-穷举

对于这种需求,首先想到的当然是穷举。由于排列的要求较少,实现更简单一些,如果我先找出所有排列,再剔除由于位置不同而重复的元素,即可实现需求。假设需要从 [A B C D E] 五个元素中取出所有组合,那么我们先找出所有元素的全排列,然后再将类似 [A B] 和 [B A] 两种集合去重即可。

我们又知道 ,那么我们先考虑一种情况 ,假设是 ,从 5 个元素中选出三个进行全排列。

被选取的三个元素,每一个都可以是 ABCDE 之一,然后再排除掉形成的集合中有重复元素的,就是 5 选 3 的全排列了。

代码是这样:

55a82b985bc67adb8cb5469605c18d55.png

对于结果组合的排重,我借用了 Java 中 HashSet 的两个特性:

元素唯一性,选取三个元素放到 Set 内,重复的会被过滤掉,那么就可以通过集合的大小来判断是否有重复元素了,

元素无序性,Set[A B] 和 Set[B A] 都会被表示成 Set[A B]。另外又由于元素唯一性,被同时表示为 Set[A B] 的多个集合只会保留一个,这样就可以帮助将全排列转为组合。可以注意得到,上面程序中 count 参数是写死的,如果需要取出 4 个元素的话就需要四层循环嵌套了,如果取的元素个取是可变的话,普通的编码方式就不适合了。

: 可变层数的循环可以用 递归 来实现。

从排列到组合-分治

穷举毕竟太过暴力,我们来通过分治思想来重新考虑一下这个问题:

分治思想

分治的思想总的来说就是”大事化小,小事化了”,它将复杂的问题往简单划分,直到划分为可直接解决的问题,再从这个直接可以解决的问题向上聚合,最后解决问题。

从 M 个元素中取出 N 个元素整个问题很复杂,用分治思想就可以理解为

首先,如果我们已经从 M 中元素取出了一个元素,那么集合中还剩下 M-1 个,需要取的元素就剩下 N-1 个。还不好解决的话,我们假设又从 M-1 中取出了一个元素,集合中还剩下 M-2 个,需要取的元素只剩下 N-2 个。直到我们可能取了有 M-N+1 次,需要取的元素只剩下一个了,再从剩余集合中取,就是一个简单问题了,很简单,取法有 M-N+1 种。如果我们解决了这个问题,已经取完最后一次了产生了 M-N+1 种临时集合,再考虑从 M-N+2 个元素中取一个元素呢,又有 M-N+2 种可能。将这些可能聚合到一块,直到取到了 N 个元素,这个问题也就解决了。

还是从 5 个元素中取 3 个元素的示例

从 5 个元素中取 3 个元素是一个复杂问题,为了简化它,我们认为已经取出了一个元素,还要再从剩余的 4 个元素中取出 2 个,求解公式为:。从 4 个元素中取出 2 个依旧不易解决,那我们再假设又取出了一个元素,接下来的问题是如何从 3 个元素中取一个,公式为 。从 3 个元素中取 1 个已经是个简单问题了,有三种可能,再向上追溯,与四取一、五取一的可能性做乘,从而解决这个问题。代码实现

用代码实现如下:

c34ebfba77e97caaf570e6dd3eec54a4.png
6765692e0f8f05e322ee90b948bb8bda.png

其实就是 递归。

直击本质-位运算

从元素的全排列找全组合,比穷举略好,但还不是最好的方法,毕竟它”绕了一次道”。

很多算法都能通过位运算巧秒地解决,其优势主要有两点:一者位运算在计算机中执行效率超高,再者由于位运算语义简单,算法大多直指本质。

组合算法也能通过位运算实现。

思想

再次考虑全组合的需求,从 M 个元素中取任意个元素形成组合,组合内元素不能重复、元素位置无关。

之前的方法都是从结果组合是否满足要求来考虑问题,考虑组合是否有重复元素、是否已有同样的组合等条件。如果换种思路,从待选元素上来考虑呢?

对于每个元素来说,它的状态就简单得多了,要么被放进组合,要么不放进组合。每个元素都有这么两种状态。如果从 5 个元素中任意取 N 个元素形成组合的话,用二进制位来表示每个元素是否被放到组合里,就是:

e807b0f0b716215ceecea0c3863d08ee.png

看到这里,应该就非常清楚了吧,每种组合都可以拆解为 N 个二进制位的表达形式,而每个二进制组合同时代表着一个十进制数字,所以每个十进制数字都就能代表着一种组合。

十进制数字的数目我们很简单就能算出来,从00000... 到 11111... 一共有 种,排除掉全都不被放进组合这种可能,结果有种。

代码实现

下面是 Java 代码的实现:

9851c340a82a807f8bb7c80be82bfa1e.png

小结

排列和组合算法在实际应用中很常见,而且他们的实现方法也非常具有参考意义。总的来说:排列用递归、组合用位运算。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/292970.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spark ML - 聚类算法

http://ihoge.cn/2018/ML2.html Spark ML - 聚类算法 1.KMeans快速聚类 首先到UR需要的包: import org.apache.spark.ml.clustering.{KMeans,KMeansModel} import org.apache.spark.ml.linalg.Vectors 开启RDD的隐式转换: import spark.implicits.…

twitter storm源码走读(五)

TridentTopology创建过程详解 从用户层面来看TridentTopology,有两个重要的概念一是Stream,另一个是作用于Stream上的各种Operation。在实现层面来看,无论是stream,还是后续的operation都会转变成为各个Node,这些Node之间的关系通…

C语言宏使用常见问题

代码&#xff1a; #include<stdio.h> #define MAX(a,b) a>b?a:b #define MIN(a,b) a>b?b:a //#define M (xY) #define M1(m) m*m #define M2(m) (m)*(m) #define M3(m) ((m)*(m)) int main(){int x,y,max,min;printf("Input one numbers:");int sum, m…

ad域管理与维护_AD域管理员账号下发

大家好&#xff0c;最近比较忙&#xff0c;好久没发文章了&#xff0c;这次继续讲AD域的相关内容。AD域运行在Windows Server服务器&#xff0c;用于集中管理网内的所有Windows客户端主机&#xff0c;其中最重要的管理手段便是「域组策略」&#xff0c;可管理的条目非常多&…

java中main函数解析

作者&#xff1a;xwdreamer出处&#xff1a;http://www.cnblogs.com/xwdreamer欢迎任何形式的转载&#xff0c;但请务必注明出处。从写java至今&#xff0c;写的最多的可能就是主函数 public static void main(String[] args) {} 但是以前一直都没有问自己&#xff0c;为什么要…

逻辑回归算法原理

http://ihoge.cn/2018/LR.html 逻辑回归模型 逻辑回归也被称为对数几率回归&#xff0c;算法名虽然叫做逻辑回归&#xff0c;但是该算法是分类算法&#xff0c;个人认为这是因为逻辑回归用了和回归类似的方法来解决了分类问题。 逻辑回归模型是一种分类模型&#xff0c;用条…

.net core入门之web应用

2019独角兽企业重金招聘Python工程师标准>>> 其实铺垫了那么久&#xff0c;终于到重点了&#xff0c;迫不及待了吧&#xff0c;那么我们用重量级工具Visual Studio 2015&#xff0c;安装Update3&#xff0c; 安装DotNetCore.1.0.1-VS2015Tools.Preview2.0.2.exe&…

python里split_python中split()的用法

原博文 2018-10-19 15:15 − Python split() 通过指定分隔符对字符串进行切片&#xff0c;如果参数 num 有指定值&#xff0c;则仅分隔 num 个子字符串。 语法&#xff1a; str.split(str"", numstring.count(str)) str -- 分隔符&#xff0c;默认为所有的空字符&…

设计模式之-命令模式(Command Pattern)

命令模式&#xff08;Command Pattern&#xff09;是用来实现在一个请求 - 响应模型松耦合。在命令模式中&#xff0c;请求被发送给调用者和调用它传递给被封装的命令对象。 Command对象将请求传递到接收器的适当的方法来执行特定操作。客户端程序创建接收器对象&#xff0c;然…

android -上传文件到服务器

android上传文件到服务器 重点:最好是设置好content-type这些参数的配置&#xff01; package com.spring.sky.image.upload.network; import java.io.DataOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.Inp…

梯度下降法、随机梯度下降法、批量梯度下降法及牛顿法、拟牛顿法、共轭梯度法

http://ihoge.cn/2018/GradientDescent.html http://ihoge.cn/2018/newton1.html 引言 李航老师在《统计学习方法》中将机器学习的三要素总结为&#xff1a;模型、策略和算法。其大致含义如下&#xff1a; 模型&#xff1a;其实就是机器学习训练的过程中所要学习的条件概率…

浅谈.NET 6 中 gRPC 的最新功能

gRPC 是一个现代的、跨平台的、高性能的 RPC 框架。gRPC 是构建在 ASP.NET Core 之上&#xff0c;也是我们推荐的使用 .NET 构建 RPC 服务的方法。.NET 6 进一步提高了 gRPC 已经非常出色的性能&#xff0c;并添加了一系列新功能&#xff0c;使 gRPC 在现代云原生应用程序中比以…

如果你没有时间读书,至少要保留这个习惯

全世界只有3.14 % 的人关注了爆炸吧知识快节奏的生活中&#xff0c;如何花费少量的时间&#xff0c;就可以让自己的生活发生好的改变&#xff1f;知乎上有一个高赞回答&#xff1a;大量阅读优质文章。见识决定了你的眼界&#xff0c;站得越高&#xff0c;看得越多&#xff0c;你…

C++ 标准模板库

转载于:https://www.cnblogs.com/Flyzhcong/p/3977865.html

.NET Conf 2021 回顾

.NET Conf 2021是有史以来规模最大的.NET Conf,全球演讲者举办了80多场会议!我们非常感谢所有收看直播、在分享会上的提问、参与我们的乐趣和游戏的人。学习将持续到1月底&#xff0c;社区活动将持续进行&#xff0c;所以一定要查看这些活动&#xff0c;并关注我们的会议 GitHu…

男厕改女厕能多敷衍......

1 搓澡时最好不要闲聊&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼2 弟弟需要充电多久才能回家&#xff1f;&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 这都什么野史&#xff1f;▼4 脚崴了怎么办&#xff1f;▼5 钥匙在老地方▼6 被红绿灯伤透…

《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果(速度可实时)...

最新的效果见 &#xff1a;http://video.sina.com.cn/v/b/124538950-1254492273.html 可处理视频的示例&#xff1a;视频去雾效果 在图像去雾这个领域&#xff0c;几乎没有人不知道《Single Image Haze Removal Using Dark Channel Prior》这篇文章&#xff0c;该文是2009年C…