蓝桥杯——Java中的全排列

全排列的概念

排列

从n个数中选取m(m<=n)个数按照一定的顺序进行排成一个列,叫作从n个元素中取m个元素的一个排列。不同的顺序是一个不同的排列。从n个元素中取m个元素的所有排列的个数,称为排列数

全排列

从n个元素取出n个元素的一个排列,称为一个全排列。全排列的排列数公式为[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gjUFMrJx-1614071860880)(https://math.jianshu.com/math?formula=n!)]

时间复杂度

n个数的全排列有n!种,每一个排列都有n个数据,所以输出的时间复杂度为O(n*n!),呈指数级,无法处理大型数据。

全排列(循环)

import java.util.ArrayList;public class 全排列_非递归 {public static ArrayList<String> getPermutation(String A) {int n = A.length();ArrayList<String> res = new ArrayList<>();res.add(A.charAt(0) + ""); // 初始化,包含第一个字符for (int i = 1; i < n; i++) {ArrayList<String> new_res = new ArrayList<>();char c = A.charAt(i); // 新字符for (String str : res) { // 访问上一趟集合中的每一个字符串// 插入到每个字符串的每个位置,形成新的字符串String newStr = c + str; // 插在前面new_res.add(newStr);newStr = str + c;// 插在后面new_res.add(newStr);for (int j = 1; j < str.length(); j++) {// 插在中间// substring(0, j) 返回下标为 0 到 j-1 的字串// substring(j) 返回下标 从 j 开始到结束的字串newStr = str.substring(0, j) + c + str.substring(j);new_res.add(newStr);}}res = new_res; // 更新res}return res;}public static void main(String[] args) {String string="abc";ArrayList<String> res=getPermutation(string);System.out.println(res);}
}

理解简单,三重for循环,复杂度极高

全排列(交换回溯)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;public class 全排列_回溯 { static ArrayList<String> res = new ArrayList<>();public static ArrayList<String> getPermutation(char[] A) { // 函数入口char[] arr = A; // 将字符串转换为字符数组Arrays.sort(arr); // 对字符数组排序getPumutationCore(arr, 0);return res;}public static void getPumutationCore(char[] arr, int k) { // 构造排列串if (k == arr.length) { // 多路递归终止条件,即排列出一种情况res.add(new String(arr));}for (int i = k; i < arr.length; i++) {// 分别确定一种字符串的第i到n位swap(arr, k, i); // 将第i位置的字符(最初字符串中)确定放置在第k位排列串中getPumutationCore(arr, k + 1); // 进行下一个位置字符的排列swap(arr, i, k);// 回溯}}public static void swap(char[] arr, int i, int j) { // 交换函数char temp = arr[i];arr[i] = arr[j];arr[j] = temp;}public static void main(String[] args) {String string = "12345";res = getPermutation(string.toCharArray());Collections.sort(res);System.out.println(res);}}

优点:简洁、重复

缺点:没有字典序 。可以对排列后的结果进行排序处理,从而解决没有字典序的问题

常用于求排列结果或者种数问题.

全排列(前缀法)

import java.util.ArrayList;
import java.util.Arrays;public class 全排列_前缀法 { static int count = 0;final static int k = 3; // 查找第k个排列static ArrayList<String> ans = new ArrayList<>();public static void permutation(String prefix, char[] arr) {// 入口,传递的arr为字符数组,prefix为空串if (prefix.length() == arr.length) { // 前缀长度==字符集的长度,一个排列就完成了count++;ans.add(prefix);if (count == k) { // 按照顺序找到第k个排列System.out.println("------" + prefix);System.exit(0);// 退出系统}}// 每次从头扫面(保证为升序),只要该字符可用,就附加到前缀后面,前缀变长了for (int i = 0; i < arr.length; i++) {char ch = arr[i]; // 获取第i个字符// 这个字符在前缀字符中出现的次数小于字符数组中出现的次时才可选if (count(prefix.toCharArray(), ch) < count(arr, ch)) {permutation(prefix + ch, arr);}}}public static int count(char[] arr, char ch) {// 计算一个字符在字符数组中出现的次数int cnt = 0;for (char c : arr) {if (c == ch) {cnt++;}}return cnt;}public static void main(String[] args) {char[] string = "34510".toCharArray();Arrays.sort(string);permutation("", string);System.out.println(ans);System.out.println(count);}
}

**优点:维持字典序 **

缺点:代码量大、复杂 。

常用于求第K个排列问题

练习(入门)

洛谷 P1706 全排列问题

题目描述

输出自然数 1 到 n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式

一个整数 n。

输出格式

由 1 ∼n 组成的所有不重复的数字序列,每行一个序列。

每个数字保留 5 个场宽。

思路

全排列,这里选择使用递归回溯的方法,选择使用Vector容器,方便最后的排序

代码

import java.util.Arrays;
import java.util.Collections;
import java.util.Scanner;
import java.util.Vector;public class 全排列问题 {private static Scanner scanner = new Scanner(System.in);private static Vector<String> res = new Vector<>(); // 自带排序函数Sortprivate static int n;public static void main(String[] args) {n = scanner.nextInt();char[] s = new char[n];for (int i = 0; i < n; i++) {Integer t = i + 1;s[i] = t.toString().charAt(0);}Arrays.sort(s);getPumutation(s, 0);Collections.sort(res);for (String string : res) {for (int i = 0; i < string.length(); i++) {System.out.print("    " + string.charAt(i));}System.out.println();}}public static void swap(char[] arr, int i, int j) { // 构造交换字符函数char temp = arr[i];arr[i] = arr[j];arr[j] = temp;}public static void getPumutation(char[] arr, int k) { // 构造排列函数if (arr.length == k)res.add(new String(arr));else {for (int i = k; i < arr.length; i++) {swap(arr, i, k);getPumutation(arr, k + 1);swap(arr, k, i);}}}
}

练习(进阶)

洛谷 P4163 [SCOI2007] 排列

题目描述

给一个数字串 s和正整数 d 统计 s 有多少种不同的排列能被 d 整除(可以有前导 00)。例如 123434有 90 种排列能被 2整除,其中末位为 2 的有 30种,末位为 4 的有 60 种。

输入格式

输入第一行是一个整数 T,表示测试数据的个数,以下每行一组 s和 d*,中间用空格隔开。s 保证只包含数字 0,1,2,3,4,5,6,7,8,9。

输出格式

每个数据仅一行,表示能被 d整除的排列的个数。

**思路:**每次数据进行全排列。再对排列结果进行筛选

import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;public class P4163_排列 {private static Scanner scanner = new Scanner(System.in);private static int N;static Set<String> conSet = new HashSet<>();static class SUM {public int count;public SUM() {count = 0;}}private static int count(char[] arr, char a) { // 计算字符出现次数int count = 0;for (int i = 0; i < arr.length; i++) {if (arr[i] == a) {count++;}}return count;}private static boolean isMod(String s, int d) { // 判断是否能整除return Long.parseLong(s) % d == 0 ? true : false;}private static boolean isRepeat(String s) { // 判断排列串是否出现过if(conSet.contains(s))return true;else {conSet.add(s);return false;}}private static void getPumutation(char[] arr, String profix, SUM sum, int d) { // 排列函数if (profix.length() == arr.length) { // 新的排列串构成if (isMod(profix, d)) {if (!isRepeat(profix))sum.count++;}}for (int i = 0; i < arr.length; i++) {char temp = arr[i];if (count(arr, temp) > count(profix.toCharArray(), temp)) {getPumutation(arr, profix + temp, sum, d);}}}public static void main(String[] args) {N = scanner.nextInt();while ((N--) != 0) {String string = scanner.next();char[] a = string.toCharArray();Arrays.sort(a);int d = scanner.nextInt();Integer countInteger = 0;SUM sum = new SUM();getPumutation(a, "", sum, d);System.out.println(sum.count);conSet.clear();//清空记录字串的容器}}}

**结果:**超时严重,只对了2个测试用例。java没有TSL中的next_permutation函数,做起来相对麻烦。网上关于java的解析暂没找到。

学习总结

Set 容器的使用**

  • HashSet Set的子接口 (散列存储) 查找速度快,易实现
  • TreeSet Set的子接口 (有序存储)—排序的类集框架 默认字母升序排列

注:TreeSet 排序是依靠Comparable接口实现的,所以保存自定义类对象时要覆写compareTo方法

class Book1 implements Comparable<Book1>{private String title;private double price;@Overridepublic int compareTo(Book1 o) {//按照价格排序if(this.price> o.price){return 1;}else if(this.price< o.price){return -1;}else {return  this.title.compareTo(o.title);}}public static void main(String[] args) {//按照价格排序Set<Book1> set = new TreeSet<>();set.add(new Book1("Java开发",990.9));System.out.println(set);
}
//其它set操作
set.clear();//清空容器
set.contains(s);//判断是否含有s

值传递与引用传递

Java中数据类型分为基本类型的引用类型两大类

基本类型: byte、short、int、long、float、double、boolean、char
引用类型: 类、接口、数组

基本类型的变量在声明时就会分配数据空间
而引用类型在声明时只是给变量分配了引用空间,并不分配数据空间

1、基本数据类型传值,对形参的修改不会影响实参
2、引用类型传引用,形参和实参指向同一个内存地址(同一个对象),所以对参数的修改会影响到实际的对象
3、String, Integer, Double等不可变的类型,可以理解为传值,最后的操作不会修改实参对象

**将基本类型实现引用传递的方法:**将基本数据类型构造成一个类的公有属性

字符串与数字的相互转换方法

//1、字符串转化为整型数字
Integer.parseInt(String s);
Integer.valueOf(String s);
//2、字符串转化为浮点型数字
Float.parseFloat(String s);
Double.parseDouble(String s);
//整形、浮点类型转化为字符串
String s = i + ""; // 方法一
String s = String.valueOf(i); // 方法二
String s = Integer.toString(i); // 方法三
//JDK中判断字符串是否为数字函数
public static boolean isNumeric(String str);

学习参考

https://blog.csdn.net/J_Jie_/article/details/109695386 对Set的使用

https://www.cnblogs.com/lmj612/p/10874052.html java 中的 值传递 与 引用传递

https://zhidao.baidu.com/question/175584476965443564.html java中如何对基本数据类型进行引用传递

https://zhidao.baidu.com/question/144544532.html java中字符串与数字的相互转换方法

https://www.jianshu.com/p/50a27d7d2972 全排列算法的理解与实现

https://www.bilibili.com/video/BV1e7411T7FV?p=114 全排列学习网课(算法很美)

蓝桥杯——Java中的全排列算法相关推荐

  1. 2014年 第5届 蓝桥杯 Java B组 省赛解析及总结

    蓝桥杯 Java B组 省赛决赛 真题详解及小结汇总[2013年(第4届)~2021年(第12届)] 第11届 蓝桥杯-第1.2次模拟(软件类)真题-(2020年3月.4月)-官方讲解视频 说明:部分 ...

  2. 2013第四届蓝桥杯Java组省赛题解析

    2013第四届蓝桥杯Java组省赛题解析 目录 第一题:高斯日记 第二题:马虎的算式 第三题:第39级台阶 第四题:黄金连分数 ​第五题:前缀判断 第六题:三部排序 ​第七题:错误票据 第八题:翻硬币 ...

  3. 2021年 第12届 蓝桥杯 Java B组 省赛真题详解及小结【第1场省赛 2021.04.18】

    蓝桥杯 Java B组 省赛决赛 真题详解及小结汇总[题目下载.2013年(第4届)~2020年(第11届)] CSDN 蓝桥杯 专栏 2013年 第04届 蓝桥杯 Java B组 省赛真题详解及小结 ...

  4. java蓝桥杯凑算是,第七届蓝桥杯JAVA B组真题解析-凑算式(第三题)

    第七届蓝桥杯JAVA B组真题解析-凑算式(第三题) 凑算式 A+B/C+DEF/GHI =10 (如果显示有问题,可以参见[图1.jpg]) 这个算式中AI代表19的数字,不同的字母代表不同的数字. ...

  5. 蓝桥杯Java历年真题与答案_蓝桥杯大赛java历年真题及答案整理(闭关一个月呕心沥血整理出来的)...

    蓝桥杯大赛java历年真题及答案整理(闭关一个月呕心沥血整理出来的) 1蓝桥杯 java 历年真题及答案整理(闭关一个月,呕心沥血整理出来的)1. 算法是这样的,如果给定 N 个不同字符,将这 N 个 ...

  6. 2017年 第08届 蓝桥杯 Java B组 决赛真题详解及小结

    ​​​​​蓝桥杯 Java B组 省赛决赛 真题详解及小结汇总[2013年(第4届)~2020年(第11届)] 第11届 蓝桥杯-第1.2次模拟(软件类)真题-(2020年3月.4月)-官方讲解视频 ...

  7. 2018年 第09届 蓝桥杯 Java B组 决赛真题详解及小结

    蓝桥杯 Java B组 省赛决赛 真题详解及小结汇总[2013年(第4届)~2020年(第11届)] 第11届 蓝桥杯-第1.2次模拟(软件类)真题-(2020年3月.4月)-官方讲解视频 说明:大部 ...

  8. 2018年 第9届 蓝桥杯 Java B组 省赛真题详解及总结

    蓝桥杯 Java B组 省赛决赛 真题详解及小结汇总[2013年(第4届)~2021年(第12届)] 第11届 蓝桥杯-第1.2次模拟(软件类)真题-(2020年3月.4月)-官方讲解视频 说明:部分 ...

  9. 2016年 第7届 蓝桥杯 Java B组 省赛解析及总结

    蓝桥杯 Java B组 省赛决赛 真题详解及小结汇总[2013年(第4届)~2021年(第12届)] 第11届 蓝桥杯-第1.2次模拟(软件类)真题-(2020年3月.4月)-官方讲解视频 说明:部分 ...

最新文章

  1. POJ3614奶牛晒阳光DINIC或者贪心
  2. Python函数定义和函数调用
  3. C机顶盒开发实战常用初始化类型:数组、结构、指针
  4. 解决yarn全局安装模块后但仍提示无法找到命令的问题
  5. 2021编程语言排行:C#飙升,Python蝉联榜首
  6. [转载]如何做到 jQuery-free?
  7. QQ注册时间查询非常准确源码程序
  8. SimpleDateFormat线程不安全及解决方案
  9. JavaScript学习(三十一)—在输入框中如何判断输入的是一个正确的网址
  10. 20200301:快乐数(leetcode202)
  11. 何恺明!再斩ICCV 2017最佳论文
  12. 201771010126 王燕《面向对象设计 java》第十五周实验总结
  13. java中bin和src文件夹_编译src中的所有文件?
  14. 如何在 Codeforces 上出题?
  15. 制作1G的U盘启动盘
  16. 常微分方程和偏微分方程
  17. word尝试打开文件时遇到错误 解决方法
  18. Learning Deep Similarity Models with Focus Ranking for Fabric Image Retrieval 学习笔记
  19. 计算机毕业论文怎样写系统的意义,毕业论文写作的目的意义及步骤-计算机论文...
  20. 小特工具箱5.0发布 增加50+个功能

热门文章

  1. SafeNet超级狗模拟破解调试
  2. 量化交易和高频交易有什么区别吗?
  3. 520小玩意之Python词云:导出与女票的微信聊天记录并分析
  4. python-docx 导出World写进内存中封装为response
  5. Go语言 Google资深工程师深度讲解
  6. 实验室三维磁场电磁铁的主要用途及技术指标
  7. 2021年Javascript最常见的面试题以及答案
  8. 聚合支付存在的问题与规范措施
  9. ChatGPT 这玩意好吓人,真能颠覆搜索引擎?
  10. sql 统计查询某一字段的某一个值的总条数