组合的示例代码 java_示例:如何遍历组合

正版包邮编程的逻辑如何面向对象

65.05元

包邮

(需用券)

去购买 >

87e65228e1283daad95013942360f171.png

这是一个再简单不过的组合问题:

编号 0-9 的 10 个球里面拿取任意 5 个,有多少种不同的组合?

答案是可以用公式算出来的,也就是 (10!) / ((5!) ^ 2) = 252 个。但是如果要把它们全部遍历出来呢?

下面是一种效率比较高的遍历方式,原理是将所有结果集看作是树节点(准确的说是叶子节点),然后去遍历这棵树即可。树的生成规则是:

一级节点的值是第一个球的编号,二级节点是第二个球的编号,依此类推;

任何一级节点的值必须大于上级节点的值。

这样能做到所有的叶子节点刚好覆盖所有的解,没有多余没有缺失。代码如下:

import java.util.Arrays;

import java.util.stream.IntStream;

/**

* 遍历组合树

*/

public class CombinationIterator {

public static void main(String[] args) {

int itemCount = 10; // 一共 10 个球

int pickCount = 5; // 取任意 5 个球

int answerCount = 0; // 可能的组合数量

// 生成第一个解,即 [0, 1, 2...]

int[] picks = IntStream.range(0, pickCount).toArray();

// 生成最后一个解

int[] lastPicks = IntStream.range(itemCount - pickCount, itemCount).toArray();

do {

if (picks != null) {

System.out.println(Arrays.toString(picks));

answerCount++;

}

picks = getNextPick(picks, lastPicks);

} while (picks != null);

System.out.printf("一共有 %d 个解。", answerCount);

}

/**

* 根据当前解计算下一个解,直到遇到最终解,则返回 null

*

* @param picks 当前解

* @param lastPicks 最终解

*

* @return 下一个解或 null

*/

private static int[] getNextPick(int[] picks, int[] lastPicks) {

if (Arrays.equals(picks, lastPicks)) {

return null;

}

int[] nextPick = Arrays.copyOf(picks, picks.length);

int movable = findMovable(nextPick, lastPicks);

nextPick[movable]++;

if (movable != nextPick.length - 1) {

// 将 movable 后面的点移回到贴紧 movable 的右侧

partialReset(nextPick, movable);

}

return nextPick;

}

// 在 picks 中寻找第一个可以右移的点

private static int findMovable(int[] picks, int[] lastPicks) {

for (int i = picks.length - 1; i >= 0; i--) {

if (picks[i] < lastPicks[i]) {

return i;

}

}

return -1; // 实际上不会返回 -1

}

// 指定位置后面的点都移回到贴紧该位置的右侧

private static void partialReset(int[] picks, int resetStart) {

for (int i = resetStart + 1; i < picks.length; i++) {

picks[i] = picks[i - 1] + 1;

}

}

}

原文链接:https://segmentfault.com/a/1190000013899418

java 11官方入门(第8版)教材

79.84元

包邮

(需用券)

去购买 >

f0f3f55624fb396b1764d42d6df88864.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值