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
问题分析:
虽然是一道简单的模拟题,但是有些地方真的让我很头疼。
- 如果一个日期是符合的,首先必须要满足日期是合法的(注意闰年的二月),还有这个日期要在题目规定范围之内。
- 因为只有三种排序情况,所以至多就三种答案。所以我们还需要做去重工作。可以定义一个唯一标识 id = (year * 100 + month) * 100 + day 。
- 还需要排序,因为要求从早到晚输出。
代码:
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 天。
满足下面条件之一的是闰年:
- 年份是 44 的整数倍,而且不是 100100 的整数倍;
- 年份是 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;
}
}