日期问题总结(Java)

1229. 日期问题

小明正在整理一批历史文献。这些历史文献中出现了很多日期。

小明知道这些日期都在1960年1月1日至2059年12月31日。

令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。

更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。

比如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。

给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?

输入格式

一个日期,格式是”AA/BB/CC”。

即每个’/’隔开的部分由两个 0-9 之间的数字(不一定相同)组成。

输出格式

输出若干个不相同的日期,每个日期一行,格式是”yyyy-MM-dd”。

多个日期按从早到晚排列。

数据范围

0≤A,B,C≤9

输入样例:
02/03/04
输出样例:
2002-03-04
2004-02-03
2004-03-02

问题分析:

虽然是一道简单的模拟题,但是有些地方真的让我很头疼。

  1. 如果一个日期是符合的,首先必须要满足日期是合法的(注意闰年的二月),还有这个日期要在题目规定范围之内。
  2. 因为只有三种排序情况,所以至多就三种答案。所以我们还需要做去重工作。可以定义一个唯一标识 id = (year * 100 + month) * 100 + day 。
  3. 还需要排序,因为要求从早到晚输出。

代码:

import java.util.*;

public class Main {
    static TreeMap<Integer,String> datemap = new TreeMap<>();//存储可能的日期和对应id

    static int[] days = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String date = scanner.nextLine(); // 获取用户输入的日期
        String[] parts = date.split("/");//将字符串分割
        //读取各个部分
        int str1 = Integer.parseInt(parts[0]);
        int str2 = Integer.parseInt(parts[1]);
        int str3 = Integer.parseInt(parts[2]);
        //年月日
        check(str1,str2,str3);
        //月日年
        check(str3,str1,str2);
        //日月年
        check(str3,str2,str1);

       for(String value : datemap.values())
           System.out.println(value);

    }

    public static void check(int year, int month, int day){
        //按照年份分配前面是19还是20
        if(year >= 60) {
            year = 1900 + year;
        } else {
            year = 2000 + year;
        }

        //检查非二月的月份日期是否合法
        if(month > 12 || day < 1 || (month !=2 && day > days[month])) return;
        //检查二月的日期是否合法
        int leap = isLeapYear(year) ? 1 : 0;
        if(month == 2 && day > days[month] + leap) return;

        //检查完成答案合法,计入map中
        String date1 = String.format("%04d-%02d-%02d", year, month, day);
        int ans = (year * 100 + month) * 100 + day;
        datemap.put(ans, date1);
    }

    public static boolean isLeapYear(int year){
        if((year % 4 == 0 && year % 100 !=0 ) || (year % 400 == 0))
            return true;
        return false;
    }

}

使用TreeMap来存储对应日期和id,方便排序和去重

使用Java中String类自带的format()方法,方便转换日期类型。

166. 回文日期

在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。

牛牛习惯用 8 位数字表示一个日期,其中,前 4 位代表年份,接下来 2 位代表月份,最后 2 位代表日期。

显然:一个日期只有一种表示方法,而两个不同的日期的表示方法不会相同。

牛牛认为,一个日期是回文的,当且仅当表示这个日期的 8 位数字是回文的。

现在,牛牛想知道:在他指定的两个日期之间(包含这两个日期本身),有多少个真实存在的日期是回文的。

一个 8 位数字是回文的,当且仅当对于所有的 i(1≤i≤8) 从左向右数的第 i 个数字和第 9−i 个数字(即从右向左数的第 i 个数字)是相同的。

例如:

  • 对于 2016 年 11 月 19 日,用 8 位数字 20161119表示,它不是回文的。
  • 对于 2010 年 1 月 2 日,用 8 位数字 20100102 表示,它是回文的。
  • 对于 2010 年 10 月 2 日,用 8 位数字 20101002 表示,它不是回文的。
输入格式

输入包括两行,每行包括一个 8 位数字。

第一行表示牛牛指定的起始日期 date1,第二行表示牛牛指定的终止日期 date2。保证 date1和 date2 都是真实存在的日期,且年份部分一定为 4 位数字,且首位数字不为 0。

保证 date1一定不晚于 date2。

输出格式

输出共一行,包含一个整数,表示在 date1 和 date2 之间,有多少个日期是回文的。

输入样例:
20110101
20111231
输出样例:
1

问题思路:

这个题目跟前面大差不差,都是考虑日期是否合法,只不过这里还需要判断是否是回文数。

代码:

import java.util.Scanner;

public class Main {
    static int[] days = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    public static boolean isPalindrome(int date){//判断是否是回文数
        int temp = date;
        int invert = 0;
        while (date != 0){
            int a = date % 10;
            invert = invert * 10 + a;
            date /= 10;
        }
        return temp == invert;
    }
    public static boolean isLeapYear(int year){//判断是否是闰年
        if((year % 4 == 0 && year % 100 !=0 ) || (year % 400 == 0))
            return true;
        return false;
    }
    public static boolean isRight(int date){//判断日期是否合法
        int day = date % 100;
        date /= 100;
        int month = date % 100;
        date /= 100;
        int year = date;

        //判断是否是闰年
        int leap = isLeapYear(year) ? 1 : 0;
        //判断除了二月之外的月份天数是否正确
        if(month > 12 || day < 1 || (month !=2 && day > days[month]))
            return false;
        //判断二月
        if(month == 2 && day > days[month] + leap)
            return false;

        //日期合法
        return true;
    }
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int date1 = scanner.nextInt();
        int date2 = scanner.nextInt();

        int cur = 0;
        for(int i = date1; i <= date2; i++){
            if(isRight(i) && isPalindrome(i))
                cur++;
        }

        System.out.println(cur);
    }
}

2867. 回文日期

20202020 年春节期间,有一个特殊的日期引起了大家的注意:20202020 年 22 月 22 日。

因为如果将这个日期按 “yyyymmdd” 的格式写成一个 88 位数是 20200202,恰好是一个回文数。

我们称这样的日期是回文日期。

有人表示 20200202 是“千年一遇” 的特殊日子。

对此小明很不认同,因为不到 22 年之后就是下一个回文日期:20211202 即 20212021 年 1212 月 22 日。

也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。

对此小明也不认同,因为大约 100100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 21212121 年 1212 月 1212 日。

算不上“千年一遇”,顶多算“千年两遇”。

给定一个 88 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。

注意: 本题数据保证一定有解。

注意

下一个回文日期和下一个 ABABBABA 型的回文日期可能是同一天。

ABABBABA 型的回文日期,需要满足 A≠B�≠�。

输入格式

输入包含一个八位整数 N�,表示日期。

输出格式

输出两行,每行 11 个八位数。

第一行表示下一个回文日期,第二行表示下一个 ABABBABA 型的回文日期。

数据范围

对于所有评测用例,10000101≤N≤8999123110000101≤�≤89991231,保证 N� 是一个合法日期的 88 位数表示。

输入样例:
20200202
输出样例:
20211202
21211212

 思路:

在前面两个的基础上再加一个判断是否为ABABBABA型即可

代码:

import java.util.Scanner;

public class Main{
    static int[] days = {0,31,28,31,30,31,30,31,31,30,31,30,31};

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int date = scanner.nextInt();
        for(int i = date + 1; ; i++){
            if(isRight(i) && isPalindrome(i)) {
                System.out.println(i);
                break;
            }
        }
        for(int i = date + 1; ; i++){
            if(isRight(i) && isAB(i)) {
                System.out.println(i);
                break;
            }
        }
    }
    public static boolean isAB(int date){
        int[] number = new int[10];
        for(int i = 8; i >= 1; i--){
            number[i] = date % 10;
            date /= 10;
        }
        if((number[1] == number[3]  && number[6] == number[8] && number[1] ==number[6]) && (number[2] == number[4]  && number[5] == number[7] && number[2] ==number[5]) && (number[1] != number[2]))
            return true;

        return false;
    }
    public static boolean isPalindrome(int date){//判断是否是回文数
        int temp = date;
        int invert = 0;
        while (date != 0){
            int a = date % 10;
            invert = invert * 10 + a;
            date /= 10;
        }
        return temp == invert;
    }
    public static boolean isLeapYear(int year){//判断是否是闰年
        if((year % 4 == 0 && year % 100 !=0 ) || (year % 400 == 0))
            return true;
        return false;
    }
    public static boolean isRight(int date){//判断日期是否合法
        int day = date % 100;
        date /= 100;
        int month = date % 100;
        date /= 100;
        int year = date;

        //判断是否是闰年
        int leap = isLeapYear(year) ? 1 : 0;
        //判断除了二月之外的月份天数是否正确
        if(month > 12 || day < 1 || (month !=2 && day > days[month]))
            return false;
        //判断二月
        if(month == 2 && day > days[month] + leap)
            return false;

        //日期合法
        return true;
    }
}

3218.日期计算

给定一个年份 y� 和一个整数 d�,问这一年的第 d� 天是几月几日?

注意闰年的 22 月有 2929 天。

满足下面条件之一的是闰年:

  1. 年份是 44 的整数倍,而且不是 100100 的整数倍;
  2. 年份是 400400 的整数倍。
输入格式

输入的第一行包含一个整数 y�,表示年份,年份在 19001900 到 20152015 之间(包含 19001900 和 20152015)。

输入的第二行包含一个整数 d�,d� 在 11 至 365365 之间。

输出格式

输出两行,每行一个整数,分别表示答案的月份和日期。

数据范围

1900≤y≤20151900≤�≤2015,
1≤d≤3651≤�≤365

输入样例1:
2015
80
输出样例1:
3
21
输入样例2:
2000
40
输出样例2:
2
9

思路:

这个还是比较保守了,只计算一年以内的,判断一下月份和是否是闰年即可

代码:

import java.util.Scanner;

public class Main{
    static int[] days = {0,31,28,31,30,31,30,31,31,30,31,30,31};

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

        int leap = isLeapYear(year) ? 1 : 0;
        int month = 0;
        while(day > 0){
            month++;
            if(month != 2){
                day -= days[month];
            }else {
                day -=days[month] + leap;
            }
        }
        if(day <= 0) {
            day += days[month];
            if(leap == 1 && month == 2) day++;
        }
        System.out.println(month + "\n" + day);
    }

    public static boolean isLeapYear(int year){//判断是否是闰年
        if((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0))
            return true;
        return false;
    }
}

  • 37
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值