🌸解题方法汇总(java B组省赛)(-1代表自己能力范围不会,直接跳过)
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
---|---|---|---|---|---|---|---|---|---|---|
第四届 | 日期(API)、吉姆拉尔森公式 | 暴力枚举 | 暴力深搜 | 递归、大数类 | 逻辑模拟 | 逻辑模拟 | 暴力查找(类集框架) | 模拟过程 | 全排列、逻辑判断、逻辑枚举的条件判断,枚举所有情况 | 题意理解,思维的巧妙运用 |
第五届 | 数学逻辑 | 数学逻辑 | 字符串、暴力模拟 | 数学、奇偶数 | 数学逻辑 | 暴力枚举 | 全排列、逻辑检查 | 模拟过程 | 深度优先、过程模拟搜索、记忆化递归 | -1 |
第六届 | 简单数学计算 | 暴力枚举 | 暴力枚举 | 模拟过程发现小技巧 | 全排列 | 数学规律 | 递归 | 模拟过程 | 递归、动态规划、矩阵快速幂 | 递归最多一万层 |
第七届 | 数学规律 | 暴力枚举 | 暴力全排列 | 组合,规律 | 递归、组合 | 暴力、全排列 | 组合、深搜、图、联通分量 | 首先暴力、暴力优化(四层到两层)哈希 | 递归模拟过程、细节很重要 | -1 |
第八届 | Excel、耐心敲代码计算、暴力计算器、 | 全排列 | 二维数组找规律 | -1 | 过程模拟分析 | 动态规划 | API、日期的细心判断(主要是细心找到每一个满足的条件) | 动态规划、扩展欧几里得、完全背包 | 数学规律、模拟过程 | 暴力、前缀和优化、取模运算 |
第九届 | 日期、计算器(注意加一天) | 暴力计算、勾股定理 | 大数类、数很大输入到文件 | 动态规划、递归、二分 | 随机快速排序、递归 | 暴力、优化(二分)、(双指针) | 画图、画过程模拟、找出数学规律、等差数列求和、绝对值的消去 | 面向对象的思维模拟、类的自定义排序、思维逻辑的严密性 | 暴力深搜、DFS查找联通分量的个数 | -1(乘法逆元) |
第十届 | 综合分析、求最大值 | 暴力求子串、Set集合 | 暴力求值、有坑(只需要关注数的后四位,不然数字太大存不了) | 暴力分解、条件判断 | 求最短路径、广度优先、深度优先、节点判断 | 暴力破解 | 模拟过程、注意合理运用变量和数组,利用二维数组和多个一维数组可以代替复杂的数据结构 | 逻辑分析与严密性、字符串正则以及API的使用 | 逻辑思维的分析与严密性、需要去考虑繁杂的所有可能的情况然后写出结果 | -1 |
第十一届 | 手工计算、代码计算时注意减法时的边界不能减到负数 | 日期、计算器、日期类 | 数学求最值、求算数不等式相等时的边界情况 | -1(找规律,用代码去模拟题目要求程序计算的过程) | 动态规划、找出存放规律与状态的转移方程 | 暴力取模、优化(位运算>>取代 / )(即n = n>> 1 相当于 n = n / 2) | 熟练使用API、StringBuilder以及字符串的判断、总的来说就是暴力模拟 | 深度优先搜索、动态规划 | 暴力拼接(双重for)、优化(二维数组、位数取取余等) | -1 |
第十二届 | 暴力查找 | 深度优先 | 数学找规律 | 数学组合(暴力组合和深搜) | 暴力尝试 | 保留两位小数以及四舍五入 |
🌸黄金分割数与斐波那契数列的关系
比较简单的一种是用连分数:
1
黄金数 = ------------------------------
1
1 + ---------------------
1
1 + -------------
1
1 + -------
1 + ...
这个连分数计算的“层数”越多,它的值越接近黄金分割数。
请你利用这一特性,求出黄金分割数的足够精确值,要求四舍五入到小数点后100位。
小数点后3位的值为:0.618
小数点后4位的值为:0.6180
小数点后5位的值为:0.61803
小数点后7位的值为:0.6180340
可以分析得出
第二层 1/2 后两位
第三层 2/3 后三位
第四层 3/5 后四位
第五层 5/8 后五位
.....
以此类推
即后100位为稳定的100多位的斐波那契数相除,则可以得出代码
import java.math.BigDecimal;
import java.math.BigInteger;
public class Main {
public static void main(String[] args) {
BigInteger a = BigInteger.ONE;
BigInteger b = BigInteger.ONE;
for(int i = 3; i < 500; i++) {
BigInteger t = b;
b = a.add(b);
a = t;
}
BigDecimal divide = new BigDecimal(a, 110).divide(new BigDecimal(b, 110), BigDecimal.ROUND_HALF_DOWN);
System.out.println(divide.toPlainString().substring(0, 103));
}
//求斐波那契
static BigDecimal fb(int n){
BigDecimal a = BigDecimal.ONE;
BigDecimal b = BigDecimal.ONE;
for (int i = 0; i < n; i++) {
BigDecimal t = b;
b = a.add(b);
a=t;
}
return b;
}
}
🌸圆周率与连分数
4 1
---- = 1 + ------------------------------
N(圆周率) 9
1 + ---------------------
25
2 + -----------------
2 + .............
double x = 111;
for(int n = 10000; n>=0; n--){
int i = 2 * n + 1;
x = 2 + (i*i / x);
}
System.out.println(String.format("%.4f", 4/ (x - 1)));
🌸吉姆拉尔森公式
private static int whatday(int y, int m, int d) {
if(m == 1) {
y--;
m = 13;
}
if(m == 2) {
y--;
m = 14;
}
return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7 + 1;
}
🌸复数幂(复数的阶乘)(了解打印流的使用文本)
复数计算的规律 尝试用 (a+bi)(c+di) = (ac - bd) + (ad + b*c)i
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.math.BigInteger;
public class Main {
public static void main(String[] args) throws FileNotFoundException {
//System.out.println(getNum(new BigInteger("2"), new BigInteger("3"), new BigInteger("2"), new BigInteger("3")));
BigInteger a = new BigInteger("2");
BigInteger b = new BigInteger("3");
BigInteger c = new BigInteger("2");
BigInteger d = new BigInteger("3");
int n = 1;
BigInteger shi;
BigInteger xu;
while(n < 123456) {
shi = a.multiply(c).subtract((b.multiply(d)));
xu = a.multiply(d).add(b.multiply(c));
n++;
a = shi;
b = xu;
}
if(b.compareTo(new BigInteger("0")) == 1) {
System.out.println(a + "+" + b + "i");
}else if(b.compareTo(new BigInteger("0")) == 0) {
System.out.println(a + "");
}else {
System.out.println(a + "" + b + "i");
}
PrintStream out = System.out;
PrintStream ps = new PrintStream(new File("ans.txt"));
System.setOut(ps);;//输出在ans.txt
System.out.println(a.toString() +b.toString() + "i");
System.setOut(out);
System.out.println(a.toString() + b.toString() + "i");
}
🌸扔鸡蛋问题(摔手机)(面试题)(动态规划)
你将获得 K 个鸡蛋,并可以使用一栋从 1 到 N 共有 N 层楼的建筑。
每个蛋的功能都是一样的,如果一个蛋碎了,你就不能再把它掉下去。
你知道存在楼层 F ,满足 0 <= F <= N 任何从高于 F 的楼层落下的鸡蛋都会碎,从 F 楼层或比它低的楼层落下的鸡蛋都不会破。
每次移动,你可以取一个鸡蛋(如果你有完整的鸡蛋)并把它从任一楼层 X 扔下(满足 1 <= X <= N)。
你的目标是确切地知道 F 的值是多少。
无论 F 的初始值如何,你确定 F 的值的最小移动次数是多少?
class 鸡蛋解法力扣 {
static Integer[][] memo = null;
static public int superEggDrop(int K, int N) {
memo = new Integer[K+1][N+1];
return dp(K,N);
}
/**
*当前K个鸡蛋共有N层楼状态时 返回这个状态下确定 F的值的最小移动次数
*/
static private int dp(int k,int n){
//base case 层数N等于0时不需要扔鸡蛋,当鸡蛋数K为1时,只能每层逐个尝试剩下所有楼层
if(k==1)return n;
if(n<=0)return 0;
//添加一个备忘录 消除之前算过的重叠子问题
if(memo[k][n]!=null)
return memo[k][n];
int tmp = Integer.MAX_VALUE;
//第一种 从第1层楼到第n层楼每层楼开始逐个尝试作为切入点 (会超时)
for(int i=1;i<=n+1;i++){
//当选择在第i层楼扔了鸡蛋之后 可能出现鸡蛋碎了和鸡蛋没碎两种情况:
//当鸡蛋碎了 问题状态转嫁为求k-1个鸡蛋 搜索的楼层区间变为1~i-1共i-1层楼时求解
int eggBreak=dp(k-1,i-1);
//当鸡蛋没碎 问题状态转嫁为鸡蛋的个数K不变 搜索楼层区间变为i+1~N共N-i层楼时求解
int eggUnBreak=dp(k,n-i);
//最终以i层为切入点求解的答案 为两种状态的最坏情况 并加上i层时操作1 并更新最小值
tmp = Math.min(tmp,Math.max(eggBreak,eggUnBreak)+1);
}
//第二种 利用二分查找的方式直接找到对应点(AC通过)
//第一种线性逐个尝试切入点 然后求每个切入点两种状态的较大值 再求这些最大值之中的最小值 其实就是求这两条单调递增和单调递减直线的交点 相当于求上半部V形山谷值 二分查找来快速寻找这个点
// int lo=1,hi =n;
// while(lo<=hi){
// int mid =(lo+hi)/2;
// int eggBreak = dp(k-1,mid-1);
// int eggUnBreak = dp(k,n-mid);
// if(eggBreak>eggUnBreak){
// hi = mid-1;
// tmp = Math.min(tmp,eggBreak+1);
// }else{
// lo = mid+1;
// tmp = Math.min(tmp,eggUnBreak+1);
// }
// }
//添加到备忘录里
memo[k][n]=tmp;
//返回当前k个鸡蛋n层楼时求解的子问题的结果
return tmp;
}
public static void main(String[] args) {
System.out.println(dp(3,1000));
}
}
x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。
x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。
如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n
为了减少测试次数,从每个厂家抽样3部手机参加测试。
某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?
请填写这个最多测试次数。
public class Main{
public static void main(String[] args) {
for(int i=0;i<10;i++)
for(int j=0;j<10000;j++)
memo[i][j] = 99999999;//找最小,初始化INF
System.out.println(f(3,1000));
//f(k,n) 当前的鸡蛋数 k
// 需要测试的楼层数 n
}
static int[][] memo = new int[10][10000];
static int f(int k,int n) {
if(k==1) //当鸡蛋数只有1时,只能线性扫描所有的楼层 n 有多少层就得扔多少次 注意题目条件是运气差。
return n;
if(n<=0) //当楼层数0是 没法扔鸡蛋
return 0;
if(memo[k][n]!=99999999) //避免重复计算
return memo[k][n];
int result=99999999;
for(int i=1;i<=n;i++) { //穷举所有的可能选择
//当选择在第i层楼扔了鸡蛋之后 可能出现鸡蛋碎了和鸡蛋没碎两种情况:
//当鸡蛋碎了 问题状态转嫁为求k-1个鸡蛋 搜索的楼层区间变为1~i-1共i-1层楼时求解
int eggBreak=f(k-1,i-1);
//当鸡蛋没碎 问题状态转嫁为鸡蛋的个数K不变 搜索楼层区间变为i+1~N共N-i层楼时求解
int eggUnBreak=f(k,n-i);
//最终以i层为切入点求解的答案 为两种状态的最坏情况 并加上i层时操作1 并更新最小值
result= Math.min(result,
Math.max(
eggBreak,eggUnBreak
)+1 //1表示在i层时要扔一次
);
}
memo[k][n]=result;
return memo[k][n];
}
}
🌸日期类(SimpleDateFormat +Date)
public static class Main{
public static void main(){
SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");
Date date1 = format.parse("1921-7-23");
Date date2 = format.parse("2020- 7-1");
int a = (int)((date2.getTime() - date1.getTime()) / 1000 * 60);//相隔多少分钟
}
}
//直接使用 Date
public static class Main{
public static void main(){
long sum = 36138 * 24 * 60L;
System.out.println(sum);
System.out.println(36138 * 24 * 60);
// long型变量在定义的时候,如果不加“L”,则默认为int型变量
Date date1 = new Date(21, 7, 23, 12, 0, 0); // 1921
Date date2 = new Date(120, 7, 1, 12, 0, 0); // 2020
long time = date2.getTime() - date1.getTime();
System.out.println(time / (60000));
}
}