Java获得一个数组的指定长度排列组合算法示例

下面详细讲解一下Java获得一个数组的指定长度排列组合算法示例的完整攻略。

算法说明

在程序设计中,经常会遇到需要从给定的元素集合中去选取一些元素,这些元素能组成的各种可能长度的排列和组合集合。这时候,排列和组合问题就变得特别重要。在Java中,提供了一些工具类帮助我们解决这些问题。

排列和组合的定义

排列问题中,给定n个元素,从中选取k个元素进行排列,若n个元素都用上,排列结果为n!,若没有全部用上,排列的结果就为n(n-1)(n-2)……(n-k+1)

组合问题中,给定n个元素,从中选取k个元素进行组合,而k个元素的顺序不再是关注点,因此总的组合结果数就是C(n,k) = n! / (k!(n-k)!).

代码实现

下面是Java实现获取一个数组的指定长度排列和组合的示例:

import java.util.ArrayList;
import java.util.Arrays;

public class CombinationPermutation {
    /**
     * 组合算法
     *
     * @param ori      原数据集合
     * @param isRepeat 是否可重复取数
     * @param result   存储结果集的集合
     * @param begin    取数的起始下标
     * @param arr      临时存储已取数的数组
     * @param count    要取的数的个数
     */
    private static void combinationAlgorithm(int[] ori, boolean isRepeat, ArrayList<ArrayList<Integer>> result, Integer begin, Integer[] arr, int count) {
        if (count == 0) {
            result.add(new ArrayList<>(Arrays.asList(arr)));
            return;
        }
        for (int i = begin; i < ori.length; i++) {
            if (!isRepeat && i > begin && ori[i] == ori[i - 1]) {
                continue;
            }
            arr[arr.length - count] = new Integer(ori[i]);
            combinationAlgorithm(ori, isRepeat, result, i + 1, arr, count - 1);
        }
    }

    /**
     * 输入原数组,指定长度,获取所有组合数
     *
     * @param ori 原数据数组
     * @param len 指定的长度
     * @return 所有组合数
     */
    public static ArrayList<ArrayList<Integer>> getCombination(int[] ori, int len) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        if (ori == null || ori.length == 0 || ori.length < len || len < 1) {
            return result;
        }
        boolean isRepeat = false;
        Integer[] arr = new Integer[len];
        Arrays.sort(ori);
        combinationAlgorithm(ori, isRepeat, result, 0, arr, len);
        return result;
    }

    /**
     * 排列算法
     *
     * @param ori      原数组
     * @param isRepeat 是否可重复取数
     * @param result   存储结果集的ArrayList
     * @param arr      临时存储已经取出的数的数组
     * @param used     用来标记数字在当前排列中是否已经出现
     */
    private static void permutationAlgorithm(int[] ori, boolean isRepeat, ArrayList<ArrayList<Integer>> result, Integer[] arr, boolean[] used) {
        if (arr.length == ori.length) {
            result.add(new ArrayList<>(Arrays.asList(arr)));
            return;
        }
        for (int i = 0; i < ori.length; i++) {
            if (!isRepeat && used[i]) {
                continue;
            }
            if (isRepeat || (!isRepeat && (i == 0 || ori[i] != ori[i - 1] || used[i - 1]))) {
                arr[arr.length - ori.length + i] = new Integer(ori[i]);
                boolean[] tmpUsed = new boolean[used.length];
                System.arraycopy(used, 0, tmpUsed, 0, used.length);
                if (!isRepeat) {
                    //当前排列已包含该数字,将used设置为true,表示在接下来的递归中不能再使用这个数字
                    tmpUsed[i] = true;
                }
                permutationAlgorithm(ori, isRepeat, result, arr, tmpUsed);
            }
        }
    }

    /**
     * 输入原数组,指定长度,获取所有排列数
     *
     * @param ori 原数据数组
     * @param len 指定长度
     * @return 所有排列数
     */
    public static ArrayList<ArrayList<Integer>> getPermutation(int[] ori, int len) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        if (ori == null || ori.length == 0 || ori.length < len || len < 1) {
            return result;
        }
        boolean isRepeat = false;
        Integer[] arr = new Integer[len];
        boolean[] used = new boolean[ori.length];
        Arrays.sort(ori);
        permutationAlgorithm(ori, isRepeat, result, arr, used);
        return result;
    }

    public static void main(String[] args) {
        int[] ori = {1, 2, 3, 3};
        ArrayList<ArrayList<Integer>> combinationResult = getCombination(ori, 2);
        ArrayList<ArrayList<Integer>> permutationResult = getPermutation(ori, 2);
        System.out.println("数组 " + Arrays.toString(ori) + " 中选取 2 个数字的所有组合:");
        System.out.println(combinationResult.toString());
        System.out.println("数组 " + Arrays.toString(ori) + " 中选取 2 个数字的所有排列:");
        System.out.println(permutationResult.toString());
    }
}

注释中已经详细解释了排列和组合算法的实现过程,以及以上代码的实现方式。上面的代码中,针对组合和排列分别对应了getCombination和getPermutation方法,其中

  • getCombination方法输入原数组和指定长度,返回一个ArrayList,包含了所有的组合结果
  • getPermutation方法输入原数组和指定长度,返回一个ArrayList,包含了所有的排列结果

在实现时,以上两个方法都是通过类似DFS的递归方式实现,通过记录已经使用的数字,避免产生重复结果。

示例说明

针对以上算法,下面通过两个示例来说明排列和组合的生成过程:

示例1:从数组[1,2,3,3] 中选取2个数字的所有组合

下面是执行结果:

数组 [1, 2, 3, 3] 中选取 2 个数字的所有组合:
[[1, 2], [1, 3], [1, 3], [2, 3], [2, 3], [3, 3]]

结果中可以看到,选择 2 个数字进行组合,共有6个答案,其包括:[1,2]、[1,3]、[1,3]、[2,3]、[2,3]、[3,3]。

示例2:从数组[1,2,3,3]中选取2个数字的所有排列

下面是执行结果:

数组 [1, 2, 3, 3] 中选取 2 个数字的所有排列:
[[1, 2], [1, 3], [1, 3], [2, 1], [2, 3], [2, 3], [3, 1], [3, 2], [3, 3], [3, 1], [3, 2], [3, 3]]

结果中可以看到,选择两个数字进行排列,共有12个答案,其包括:[1,2]、[1,3]、[1,3]、[2,1]、[2,3]、[2,3]、[3,1]、[3,2]、[3,3]、[3,1]、[3,2]、[3,3]。

至此,我们已经详细讲解了Java获得一个数组的指定长度排列组合算法的完整攻略,希望这里的示例和说明对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java获得一个数组的指定长度排列组合算法示例 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • Java SpringBoot整合SpringCloud

    Spring Boot和Spring Cloud是两个非常流行的Java框架,它们可以帮助开发者快速构建分布式应用程序。在本攻略中,我们将详细介绍如何将Spring Boot和Spring Cloud整合在一起,并提供两个示例来说明其用法。 以下是两个示例,介绍如何将Spring Boot和Spring Cloud整合在一起: 示例一:使用Spring Cl…

    Java 2023年5月15日
    00
  • Sprint Boot @CacheEvict使用方法详解

    在Spring Boot中,@CacheEvict注解用于从缓存中删除数据。使用@CacheEvict注解可以指定在何时从缓存中删除数据,例如在更新数据时。本文将详细介绍@CacheEvict注解的作用和使用方法,并提供两个示例说明。 @CacheEvict注解作用 在Spring Boot中,@CacheEvict注解的作用是从缓存中删除数据。使用@Cac…

    Java 2023年5月5日
    00
  • MyBatis框架之mybatis逆向工程自动生成代码

    MyBatis框架之mybatis逆向工程自动生成代码完整攻略 什么是逆向工程 逆向工程是指通过数据库的表结构自动生成Java代码的过程。在Web开发中,Java开发人员通常会和数据库打交道,而每次手写一个POJO类、DAO类和Mapper文件比较繁琐,如果能够快速地生成这些代码,开发效率可以得到显著提升。MyBatis框架提供了逆向工程工具用于自动生成Ja…

    Java 2023年5月20日
    00
  • 关于Java中方法重载和方法重写

    方法重写是子类继承父类(默认继承Object类)后覆盖父类的方法 需要保证同名 同参 同返回值 且访问权限范围不能缩小(public>protected>default>private) public class Father{ public int method(){ return -1; } } class Son extends Fa…

    Java 2023年4月22日
    00
  • Spring Data JPA框架的Repository自定义实现详解

    Spring Data JPA是Spring框架中用于简化JPA的使用的框架,其底层依赖了Hibernate。而Spring Data JPA框架的Repository接口提供了许多内置的方法来完成数据访问的功能,但如果需要执行一些特殊的查询操作,我们需要自定义Repository实现。下面我们详细介绍如何自定义Repository实现。 1. 创建自定义R…

    Java 2023年5月20日
    00
  • Mybatis输入输出映射及动态SQL Review

    Mybatis输入输出映射及动态SQL Review Mybatis是一个基于Java的持久化框架,支持定制化SQL、存储过程以及高级映射。在Mybatis中,输入输出映射是指将Java对象与SQL语句的参数或结果集进行转换的机制,而动态SQL则可根据需要构建不同的SQL语句。 输入输出映射 输入输出映射主要涉及Mybatis中的ParameterHandl…

    Java 2023年5月19日
    00
  • 详解java中的四种代码块

    下面为您详细讲解“详解Java中的四种代码块”的攻略。 代码块 在Java中,代码块是一段被一对花括号包围的代码。Java中共有四种类型的代码块: 普通代码块 静态代码块 同步代码块 构造代码块 下面我们将分别对这四种代码块进行介绍。 普通代码块 普通代码块是被一对花括号包围的代码块,它可以出现在方法中、类中、循环体中等。 public class Code…

    Java 2023年5月30日
    00
  • JavaScript解析JSON数据示例

    下面是关于“JavaScript解析JSON数据示例”的完整攻略。 什么是JSON数据格式 JSON指的是JavaScript对象表示法(JavaScript Object Notation),它是一种轻量级的数据交换格式。它易于人们阅读和编写,同时也易于机器解析和生成。在很多网站中,JSON已成为主流的数据格式之一。 具体来说,JSON数据格式是由一系列键…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部