首页 > 编程语言 >排列的字典序问题(Java)

排列的字典序问题(Java)

时间:2024-04-01 20:31:09浏览次数:29  
标签:排列 Java int list long static 字典

问题描述:

n个元素{1,2,…,n}有n!个不同的排列。将这n!个排列按字
典序排列,并编号为0,1,…,n!-1.每个排列的编号为其字典序值。例如,当
n=3时,6个不同排列的字典序值如下:

字典序值排列    0       1       2        3       4        5
                     123    132    213    231    312    321
算法设计
给定n及n个元素{1,2,…,n}的一个排列,计算出这个排列的字典
序值,以及按字典排列的下一个排列。

数据输入和数据输出
数据输入:第1行是元素个数n。接下来的1行是n个元素{1,2,…,n}的一个排列。

结果输出:第一行是字典序值,第2行是按字典序排列的下一个排列,如果不存在则输出-1

        输入文件示例                输出文件示例 
       8                                   8227
       2 6 4 5 8 1 7 3              2 6 4 5 8 3 1 7

问题一

本题可以与全排列问题一起思考。本题与全排列问题不同点在于swap函数,也就是交换方式不同。全排列中,如:123,把3放前面来是直接与1换位置,但是字典序里,3是被插进前面去的,并不是换前面去的。全排列的输出为:

123
132
213
231
321
312

发现最后2行没有,与字典序的排序不同,这就是问题所在。

因此我们的swap函数应该为:

 private static void Swap2(int[] list, int k, int m) {     //将元素还回去
        int temp = list[k];
        for (int i = k; i < m; i++) {
            list[i] = list[i + 1];
        }
        list[m] = temp;
    }

    private static void Swap1(int[] list, int k, int m) {      //将元素排到最前面
        int temp = list[m];
        for (int i = m; i > k; i--) {
            list[i] = list[i - 1];
        }
        list[k] = temp;
    }

 这里写了两个swap函数,因为插回去以后,还得还回去,但是2个函数并不通用。

 问题二

了解次序的运算规律,这里次序是由逆序数来运算的,我们以3412为例子。逆序数就是指前面的数大于后面的数。

 3大于后面的1和2,因此3的逆序数为2;4大于后面的1和2,因此4的逆序数也为2;1后面没有比它小的,所以为0;2后面没有数了,因此也为0。所以3412的次序就为,2*3!+2*2! = 12+4=16。(逆序数后面的为该数后面有几位数的阶乘)

我们再举例一个:2341,首先2仅大于后面的1,然后3也仅大于后面的1,4同理。得:1*3!+1*2!+1*1!=6+2+1=9。

通过以上2个例子我相信你已经掌握次序的运算规律了。下面给出根据这些规律写出的代码。

 public static long Function(int i, int n, int[] list){
        if(i == list.length)
            return 0;
        return Function(i + 1, n, list) + (order(list[i], list, i + 1) - 1) * factorial(n - i -1);
    }

    private static long factorial(int n) {          //阶乘
        long result = 1;
        for (int i = 2; i <= n ; i++) {
            result *= i;
        }
        return result;
    }

    private static int order(int num, int[] list, int start) {     //计算逆序数,对于每个元素计算后面有多少元素比它小
        int count = 1;
        for (int i = start; i < list.length; i++) {
            if(list[i] < num)
                count++;
        }
        return count;
    }

除了这种做法,我们也可以全排列出来,用count记录这是第几个,在每次排列前判断一下,如果符合这种排序就输出count,但是代码效率会偏低。(这里这种方法的代码只需要在我完整代码里perm函数中加个比对就好)

完整代码展示

这里放出完整代码供参考:

package com.chenhao.Demo;

import java.util.Scanner;

public class Dictionary {
    public static long Count = 0;
    public static long judge = 0;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();

        int[] list = new int[n];
        for (int i = 0; i < list.length; i++) {
            list[i] = sc.nextInt();
        }

        System.out.println("次序为:" + Function(0, n, list));

        judge = Function(0, n, list);

        for (int i = 0; i < list.length; i++) {      //将数组初始化
            list[i] = i + 1;
        }

        perm(list,0, n - 1);

    }

    public static long Function(int i, int n, int[] list){
        if(i == list.length)
            return 0;
        return Function(i + 1, n, list) + (order(list[i], list, i + 1) - 1) * factorial(n - i -1);
    }

    private static long factorial(int n) {          //阶乘
        long result = 1;
        for (int i = 2; i <= n ; i++) {
            result *= i;
        }
        return result;
    }

    private static int order(int num, int[] list, int start) {     //计算逆序数,对于每个元素计算后面有多少元素比它小
        int count = 1;
        for (int i = start; i < list.length; i++) {
            if(list[i] < num)
                count++;
        }
        return count;
    }

    public static void perm(int[] list, int k, int m){     //产生list[k:m]的所有排列
        if(k == m ){
            if (Count == judge + 1) {
                for (int i = 0; i <= m; i++) {
                    System.out.print(i == m ? list[m] : list[i] + " ");
                }
                System.out.println();
            }
            Count++;
        }else {
            for (int i = k; i <= m ; i++) {
                    Swap1(list, k, i);
                    perm(list, k + 1, m);
                    Swap2(list, k, i);
            }
        }
    }

    private static void Swap2(int[] list, int k, int m) {     //将元素还回去
        int temp = list[k];
        for (int i = k; i < m; i++) {
            list[i] = list[i + 1];
        }
        list[m] = temp;
    }

    private static void Swap1(int[] list, int k, int m) {      //将元素排到最前面
        int temp = list[m];
        for (int i = m; i > k; i--) {
            list[i] = list[i - 1];
        }
        list[k] = temp;
    }
}

标签:排列,Java,int,list,long,static,字典
From: https://blog.csdn.net/2201_75609050/article/details/137084542

相关文章

  • 字典案例
    #案例1:#假设,已知小明、小红、小亮三人的语文、数学、英语三科成绩,将姓名、学科、成绩做对应,并计算谁的总分最高  #案例2:#假设,已知小明、小红、小亮三人的语文、数学、英语三科成绩,将姓名、学科、成绩做对应,并计算谁的总分最高  ......
  • Javascript
    JS的引入方式<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>js的引入方式</title&......
  • 初学Java,HelloWorld
    1、开发三步骤1.1程序开发步骤说明        JDK安装完毕,可以开发我们第一个Java程序了。        Java程序开发三步骤:编写、编译、运行。1.2编写Java源程序保存.java源文件在电脑中目录新建文本文件,完整的文件名修改为HelloWorld.java,其中文件名为Hello......
  • JUC:java内存模型(如何保证?可见性、原子性、有序性)
    文章目录java内存模型可见性解决方法原子性有序性流水线技术模式之Balking(犹豫)java内存模型JMM即JavaMemoryModel,它定义了主存、工作内存抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等。JMM体现在以下几个方面:原子性-保证指令不......
  • python基础(四)----列表、字典练习题
    好友管理系统请设计一个好友管理系统,每个功能都对应一个序号,用户可根据提示“请输入您的选项”选择序号执行相应的操作,包括:(1)添加好友:用户根据提示“请输入要添加的好友:”输入要添加好友的姓名,添加后会提示“好友添加成功”。(2)删除好友:用户根据提示“请输入删除好友姓名:”输入要删......
  • Python列表、字典、元组练习题
    一、将下列姓名长度小于2字符的删除,将写法不同但名字一样的名字合并,并按首字母大写形式输出。names=[‘Bob’,‘JOHN’,‘alice’,‘bob’,‘ALICE’,‘J’,‘Bob’]答案:names=['Bob','JOHN','alice','bob','ALICE','J','Bob']ans={name.title()for......
  • java计算机毕业设计(附源码)医患辅助系统(ssm+mysql+maven+LW文档)
    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:随着信息技术的飞速发展,医疗健康领域正经历着前所未有的变革。传统的医患交流模式受限于时间和空间,难以满足现代社会对医疗服务效率和质量的要求。医患辅......
  • java计算机毕业设计(附源码)医疗大数据系统(ssm+mysql+maven+LW文档)
    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:医疗大数据系统是近年来在医疗领域内兴起的一个重要研究方向,它利用现代信息技术手段,对海量的医疗健康数据进行采集、存储、管理和分析,以期提供更为精准、......
  • (自学#Python)Day08-字典的定义及基本操作
    (自学Python)Day08-字典的定义及基本操作一、字典的定义及创建"""字典dict定义:由一系列键值对组成的可变散列容器。操作:创建添加定位删除遍历"""#1.创建#列表善于存储单一......
  • Java版商城:Spring Cloud+SpringBoot b2b2c电子商务平台,多商家入驻、直播带货及免 费
    随着互联网的快速发展,越来越多的企业开始注重数字化转型,以提升自身的竞争力和运营效率。在这个背景下,鸿鹄云商SAAS云产品应运而生,为企业提供了一种简单、高效、安全的数字化解决方案。鸿鹄云商SAAS云产品是一种基于云计算的软件服务,旨在帮助企业实现业务流程的自动化和优化。......