🌸记录蓝桥杯javaB组历届决赛真题解题算法总结与对比
🌸解题方法汇总(java B组决赛)
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
---|---|---|---|---|---|---|---|---|---|---|
第四届 | 暴力枚举 | 暴力枚举 | 快速排序 | BFS、双向BFS、八数码问题、康托展开等 | 动态规划、模拟 | -1 | - | - | - | - |
第五届 | 暴力枚举 | 全排列+剪枝(或者直接暴力但是代码剪枝量很大) | 读题、细心、逻辑模拟 | 康托展开式(不会则直接暴力全排,但是分不高,可能一半都没有而且超时)、阶乘 | 行列式、矩阵乘法、模拟、扩展欧几里得 | -1 | - | - | - | - |
第六届 | 脑筋转弯+暴力计算 | 全排列+判断 | 自己的方法是“猜”“试出来” | 深度优先搜索 | -1 | -1 | - | - | - | - |
第七届 | 画图找出规律后使用递归模拟过程 | 全排列 | 代码分析,考你能不能读懂代码 | 回溯+剪枝 | 暴力搜索(超时);DFS+剪枝回溯(60);动态规划(80);数据结构(100) | -1 | - | - | - | - |
第八届 | 直接暴力循环 | 使用另一个数组进行模拟细胞增殖的过程或者使用深度优先模拟 | 读代码找规律(看自己的细心程度吧) | 直接模拟计算的过程,注意使用数据范围较大的Long,而且需要熟练使用Long、Integer等类的API | 博弈问题、深度优先、剪枝,回溯、模拟 | -1 | - | - | - | - |
第九届 | 海伦公式 | 全排列、剪枝判断 | 全排列、回溯 | 并查集、连通分量、递归 | 构造树或者递归优化 | -1 | - | - | - | - |
第十届模拟 | 暴力+熟悉除模运算的实质 | 暴力或者深搜求子串 | 暴力(时间长)、找规律分析题,将除模转换成次方 | 暴力深搜(耗时加分低)、找规律理解最大公约数的含义 | 并查集、联通分量找环 | -1(暴力只能30) | - | - | - | - |
第十届 | 暴力 | 素数筛、记忆化深搜或者dp | 找规律 | 素因子分解、找规律 | 深搜+判重 | dp+贪心 | 暴力或者dp | -1(找规律) | 线段树、主席树、树状数组 | -1 |
🌸康托展开
康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。
通俗简介:
康托展开可以求解一个排列的序号,比如:12345 序号为 1 ,12354序号为2,按字典序增加编号递增,依次类推。
康托逆展开可以求解一个序号它对应的排列是什么。
先给出康托展开的公式:
$X = a_n(n - 1)!+ a_{n-1}(n-2)!+….+a_1\cdot0!$
先对这个公式里变量进行解释,大家不理解这个公式没关系,慢慢往后看,很简单的。 的意思是从右往左数第 i 位这个数是这个数前未出现的数,第
大。举个例子就明白这个公式了:
注意:计算的时候 12345 序列应视为第0个序列,后面会解释为什么。
1 | 百度百科的例子 |
拿52413举例子:
1、首先看第一个数 5,不管第一位是什么数,后面都有四位数,那么这四位数全排列的方式有 4!种,而如果第一位是 1 或 2 或 3 或 4 都会比5开头的字典序要小,所以可以令1,2,3,4分别作为开头,这样的话就会有 4 * 4!种排法要比 52413这种排法的字典序要小。
那么第一个数是1,2,3,4时候的字典序的个数数完了是 4 * 4! 种,且这些字典序都要比52413的字典序要小。
还有其他的排列方式比52413的字典序要小的吗?
2、那么就可以固定第一位5,找下一位2,这时5已经用过了,所以从剩下的 1,2,3,4 里挑选比2小的数,一共1个,后面还剩三位,也就是3!种排列方式,那么这时候比 52413 字典序要小的又有 1 * 3!种,也就是当5在第一位,1在第二位的时候。
3、再看第三位4,这时5,2都用了,所以从剩下的 1,3,4三个数中找比4小的数的个数,有两个比4小原理同上,所以这时候也可以有 2 * 2!种排列方式的字典序小于 52413
4、再看第四位1,这时候会有 0 * 1!种
5、再看第五位3,这时候会有0 * 0!种
综上所述:
对于序列: 52413 该序列展开后为: 4 * 4! + 1 * 3! + 2 * 2! + 0 * 1! + 0 * 0! ,计算结果是: 106
由于是从0开始计数的,所以最后 52413 的编号为 107
为什么从0开始计数?
可以这样看:我现在让你求12345的康托展开值,也就是:04!+ 03!+ 02!+ 01!+0*0! = 0 所以明白了吧~~
康托公式最小字典序的编号就是0。
1 | /***** 这里以字符串进行展示 字符串可泛化性好 ******/ |
🌸康托逆展开
直接开栗子:
如果初始序列是12345(第一个),让你求第107个序列是什么。(按字典序递增)
这样计算:
先把107减1,因为康托展开里的初始序列编号为0
然后计算下后缀积:
1 2 3 4 5
5! 4! 3! 2!1! 0!
120 24 6 2 1 1
106 / 4! = 4 ······ 10 有4个比它小的所以因该是5 从(1,2,3,4,5)里选
10 / 3! = 1 ······ 4 有1个比它小的所以因该是2 从(1, 2, 3, 4)里选
4 / 2! = 2 ······ 0 有2个比它小的所以因该是4 从(1, 3, 4)里选
0 / 1! = 0 ······ 0 有0个比它小的所以因该是1 从(1,3)里选
0 / 0! = 0 ······ 0 有0个比它小的所以因该是3 从(3)里选
所以编号107的是 52413
康托逆展开代码:
1 | /***** 这里以字符串进行展示 字符串可泛化性好 ******/ |
🌸吉姆拉尔森公式
1 | private static int whatday(int y, int m, int d) { |
🌸海伦公式
1 | 三角形三边长a, b, c |
🌸素数
1 | /** |
🌸日期类(SimpleDateFormat +Date)
1 | public static class Main{ |
1 | //直接使用 Date |