Java技巧

目录

日期类

计算时间差(LocalDateTime)

遍历某段日期

大数据处理 

常用数学技巧和基础 

快速幂

最大公约数和最小公倍数

进制转换

求质数


日期类

蓝桥杯比赛中经常出现的有关日期问题的题目,通常需要大量的代码判断日期,非常不方便。Java为我们封装好了日历类Calender省去了大量的代码编写,使用该类能够让日期问题变得十分简单~

创建Calender实例

使用 Calender 的工厂方法 :Calender.getInstance()获取Calender实例:

public static void main(String[] args) throws IOException {
    Calendar calendar = Calendar.getInstance();
}

Calender类字段说明

Calender字段需要额外注意,有的字段常量值与日常使用有所区别:

上面标记为红色的字段,一定要注意与现实生活中使用的不同。

设置Calender时间

Calendar 中 set 和 get 时间都是通过在参数中填入不同的字段来实现的,

这里设置时间为**2001年10月23日12时12分12秒** 举例说明

public static void main(String[] args) throws IOException {
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.YEAR, 2001);
    // 月份需要注意对应!!
    calendar.set(Calendar.MONTH, 9);
    calendar.set(Calendar.DATE, 23);
    calendar.set(Calendar.HOUR_OF_DAY, 12);
    calendar.set(Calendar.MINUTE, 12);
    calendar.set(Calendar.SECOND, 12);
}

同时按照代码执行的顺序,位于后方日历的设置会覆盖前面日历的设置,就例如:

public static void main(String[] args) throws IOException {
    Calendar calendar = Calendar.getInstance();
    // 前面修改年份的设置
    calendar.set(Calendar.YEAR, 2001);
    calendar.set(Calendar.MONTH, 9);
    calendar.set(Calendar.DATE, 23);
    calendar.set(Calendar.HOUR_OF_DAY, 12);
    calendar.set(Calendar.MINUTE, 12);
    calendar.set(Calendar.SECOND, 12);
    calendar.set(Calendar.WEEK_OF_YEAR, 3);

    // 一个修改年份的设置
    calendar.set(Calendar.YEAR,2021 );
    System.out.println(calendar.getTime());
}

运行出来的结果为:

Mon Jan 11 12:12:12 CST 2021

Calender获取值

public static void main(String[] args) throws IOException {
    Calendar calendar = Calendar.getInstance();

    calendar.get (Calendar.YEAR);//年 
    calendar.get (Calendar.MONTH) + 1;//月 ,1月对应0,2月对应1,因此需要+1
    calendar.get (Calendar.DATE);//日 
    calendar.get (Calendar.HOUR_OF_DAY);//时 
    calendar.get (Calendar.MINUTE);//分 
    calendar.get (Calendar.SECOND);//秒 
    calendar.get (Calendar.DAY_OF_WEEK);//星期,周日是1,剩下自己推算)
}

计算时间差(LocalDateTime)

/**
 * @param args 两个日期相差的天数
 * 求2022-2-1到2022-3-1相差的天数
 * 求两个日期的时间差(可以以天、小时、分钟、秒为单位输出)
 */
 public static void main3(String[] args) {
    LocalDateTime time1 = LocalDateTime.of(2022, 2, 1, 0, 0);
    LocalDateTime time2 = LocalDateTime.of(2022, 3, 1, 0, 0);
    long result = Duration.between(time1, time2).toDays(); // 28

    LocalDateTime time3 = LocalDateTime.of(2022,5,13,13,13,59,23);
    LocalDateTime time4= LocalDateTime.of(2022,5,14,13,13,59,23);
    int res = (int) Duration.between(time3,time4).toMinutes();
 }

遍历某段日期

    /**
     * @param args 遍历某段日期的每一天
     *
     * 遍历2022-01-01到2022-03-01这段日期中的每一天
     *
     * 例题:跑步锻炼
     * 正常情况下,小蓝每天跑 1 千米.如果某天是周一或者月初(1 日),为了激励自己,小蓝要跑 2 千米.
     * 如果同时是周一或月初,小蓝也是跑 2 千米.
     * 小蓝跑步已经坚持了很长时间,从 2000 年 1 月 1 日周六(含)到 2020 年 10 月 1 日周四(含).
     * 请问这段时间小蓝总共跑步多少千米?
     */
    public static void main4(String[] args) {
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, 2000);
        c.set(Calendar.MONTH, 0);
        c.set(Calendar.DAY_OF_MONTH, 1);
        int res = 0;
        for(;;){
            if(c.get(Calendar.DAY_OF_WEEK) == 2 || c.get(Calendar.DATE) == 1){
                res += 2;
            }else{
                res += 1;
            }
            if(c.get(Calendar.YEAR) == 2020 && c.get(Calendar.MONTH) == 9 &&
                    c.get(Calendar.DAY_OF_MONTH) == 1){
                break;
            }
            c.add(Calendar.DATE, 1);//天数自增1
        }
        System.out.println(res);
    }
    /**
     * 方法二:模拟
     */
    static int[] M = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    public void paobu() {
        int y = 2000, m = 1, d = 1, w = 6, ans = 0;
        while (y != 2020 || m != 10 || d != 1) {
            if (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) {//判断闰年
                M[2] = 29;
            } else {
                M[2] = 28;// M是全局变量
            }
            d++;
            w = (w + 1) % 7;// w为0为星期天
            if (d > M[m]) {
                d = 1;
                m++;
            }
            if (m > 12) {
                m = 1;
                y++;
            }
            if (d == 1 || w == 1) {
                ans++;// 是月初或者周一多加一次
            }
            ans++;
        }
        // 这个循环是先加值再加日期,所以2020.10.1号的已经加上去了,但是2000.1.1没加上,所以加2
        ans += 2;
        System.out.println(ans);// 8879
    }
    /**
     * 1999年12月31日是星期五,请问:未来哪一个离我们最近的一个世纪末年(即XX99年)的12月31日
     * 正好是星期天?回答年份
     */
    public void judgeYear() {
        // 注意Calendar实例的获取方式
        Calendar calendar = Calendar.getInstance();
        for (int year = 1999; year < 10000; year += 100) {
            // 设置年月日
            calendar.set(Calendar.YEAR, year);
            calendar.set(Calendar.MONTH, 11);// 其实是12月
            calendar.set(Calendar.DAY_OF_MONTH, 31);
            if (calendar.get(Calendar.DAY_OF_WEEK) == 1) {
                // sunday是第一天,所以为1时是Sunday,通过源码查看
                System.out.println(year);// 2299
                break;
            }
        }
    }

判断闰年

(四年一闰 && 百年不全闰)|| 四百年又闰。

if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) {

大数据处理 

你一定听说过这个故事。国王对发明国际象棋的大臣很佩服,问他要什么报酬,大臣说:请在第 1个棋盘格放 1 粒麦子,在第 2 个棋盘格放 2 粒麦子,在第 3 个棋盘格放 4 粒麦子,在第 4 个棋盘格放 8 粒麦子,......后一格的数字是前一格的两倍,直到放完所有棋盘格(国际象棋共有 64 格)。

国王以为他只是想要一袋麦子而已,哈哈大笑。

当时的条件下无法准确计算,但估算结果令人吃惊:即使全世界都铺满麦子也不够用!

请你借助计算机准确地计算,到底需要多少粒麦子。

    public static void main(String[] args) {
		BigInteger a = new BigInteger("1");
		BigInteger b = new BigInteger("2");
		BigInteger res = new BigInteger("1");
		for (int i = 2; i <= 64; i++) {
			a = a.multiply(b);
			res = res.add(a);
		}
		System.out.println(res);//18446744073709551615
		System.out.println(Integer.MAX_VALUE);//2147483647
	}

数列求值

给定数列 1, 1, 1, 3, 5, 9, 17,……从第 4 项开始,每项都是前 3 项的和。 求第 20190324 项的最后 4 位数字。

    public static void main(String[] args) {
		int a = 1;
		int b = 1;
		int c = 1;
		int d = 0;
		for (int i = 4; i <= 20190324; i++) {
			d = a + b + c;
			d = d % 10000;
			a = b;
			b = c;
			c = d;
		}
		System.out.println(d);//4659
	}

常用数学技巧和基础 

快速幂


虽然可以使用Java数学包下的Math.pow方法来求出x的n次幂的值,但这个函数本身运行起来是非常耗时的;对于需要参加竞赛的,无疑会在超时的边缘徘徊,而快速幂可以通过将指数拆分成多个因数相乘的形式来简化幂运算,大大调高运算效率!

    public double myPow(double x, int n) {
        double result = 1;
        long v = n;// 为了保证-n不溢出,先转换成long类型

        if(v < 0) {// 如果v小于0, 求1/x的-v次方
            x = 1 / x;
            v = -v;
        }
        while(v > 0) {
            if((v & 1) == 1) {//此处等价于if(v % 2 == 1)
                result *= x;
            }
            v >>= 1;//此处等价于v = v / 2
            x *= x;
        }
        return result;
    }

最大公约数和最小公倍数

蓝桥杯的数据量是出名的大(这个后面会体现),超时是肯定的。
背下欧几里得公式直接使用(已知效率最快求出公倍数地公式)

    /**
     * gcd函数(欧几里得算法原理)
     * @return 返回值则是a和b的最大公约数
     */
    public static int gcd(int a,int b){
        return b == 0 ? a : gcd(b,a % b);
    }

    /**
     * lcm函数(速求最小公倍数,原理基于gcd函数)
     * @return 返回值为a和b的最小公倍数
     */
    public static int lcm(int a, int b){
        return (a * b) / gcd(a,b);//最小公倍数 = 两数之积 ÷ 两数最大公约数
    }

进制转换

    public static void conversion(){
        //n进制转为十进制
        System.out.println(Integer.valueOf("1111",2));//15
        System.out.println(Integer.valueOf("ffff",16));//65535
        //十进制转为n进制
        System.out.println(Integer.toString(128,2));//10000000
        System.out.println(Integer.toString(15,16));//f
    }

求质数

1.判断一个数是否是质数

    private static boolean isPrime(int n){
        int i = 2;
        for(i = 2;i <= Math.sqrt(n);i++){
            //只要模一次是0,就不是素数
            if(n % i == 0){
                return false;
            }
        }
        return i > Math.sqrt(n);//是素数
    }

2.求n下有多少个质数

埃筛法
埃筛法是能够快速筛选出质数的方法之一,在众多质数筛选方法中,埃筛法虽然不是最快的方法,但绝对是最容易理解的方法。
原理:从小到大开始筛选质数,当某个数被认定为质数时,那么后面能够被该数整除的数就一定不是质数,为这些数增加一个标记,当遍历到这些被标记的数时,直接跳过即可,无需再为其执行检验是否为质数的操作,因为判断一个数是否为质数是筛选质数过程中最耗时的操作,而埃筛法则能大幅度的减少该操作的执行频率,从而提高素数筛选的效率。

    public static void prime(int n) {
        boolean[] flag = new boolean[n + 1];
        for(int i = 2; i <= n; i++) {
            if(flag[i]){
                continue;
            }
            System.out.print(i + "  ");
            for(int j = i; i * j <= n; j++) {
                flag[i * j] = true;
            }
        }
    }
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值