算法:回文日
12月2日,浏览资讯的时候无意间发现了李永乐老师在Bilibili发了一条动态。
这完全勾起了我的兴趣,便用实验课时间写代码计算一下(所谓写代码半小时,改BUG一下午)
当时由于刚刚进入面向对象不久,也没有学习Date和日历的常用类,所以使用的方法是一般的字符串的方法,在最后有使用SimpleDateFormat的方法。
-
使用一般方法
//首先定义今天(12月2日)的日期 static int year = 2021; static int month = 12; static int day = 2; //由于整数类型会忽略没有意义的“0”,所以需要将数字类型转化为字符串,然后补齐“0” String yearstr = String.valueOf(year); String monthstr = String.valueOf(month); String daystr = String.valueOf(day); if (monthstr.length() == 1) { monthstr = 0 + monthstr; } if (daystr.length() == 1) { daystr = 0 + daystr; }
String date =yearstr+monthstr+daystr;
之后是最关键的步骤:date字符串是否满足回文日的格式,以及date字符串是否是一个日期。
满足天数,则必须大月时,天数不大于31天,小月时,天数不大于30天。平年时,2月的天数不大于28天,闰年的时候,2月的天数不超过29天。
//这里定义了一个方法,用来检测是否是年月日。 public static boolean fix(int month, int day) {
//如果当前是大月,则天数不能超过31天。 if ((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)) { if (day <=31) { return true; }
//如果当前是小月,则天数不能超过30天 } else if ((month == 4 || month== 6 || month == 9 || month == 11)) { if (day <= 30) { return true; } } else if (month == 2) { //如果当前是2月份,那么闰年的时候,天数不能超过29天,平年则不超过28天。闰年的定义指的是年份是4但不是100的倍数,或者是400的倍数。 if ((year % 4 == 0&&year%100!=0)||(year%400==0)) { if (day <= 29) { return true; } } else{ if (day <= 28) { return true; } } } return false; }
做完做些之后我们只要对字符串进行比较。
字符串是yyyyMMdd的形式,只要满足字符串下标为0的字符和7相同,1和6相同…即可。在里面进行计数,最后让day进行自增或者自减。
if(flag&&date.charAt(0)==date.charAt(7)&&date.charAt(1)==date.charAt(6)&&date.charAt(2)==date.charAt(5)&&date.charAt(3)==date.charAt(4)){ //这里的flag是上一个方法的返回值。
System.out.println(date);
num++;
}
day++;//day--;
最后需要对天数进行校验。如果day在大月时超过31则月数+1,小月时超过30月数也+1。2月需要分平年和闰年。
//这里定义了两个方法,分别对应day的自增和自减,这里以自减举例。 //当前月的上一个月是大月时,将天数变为31,月数-1。如果此时月数是0,则年数-1,月数变为12。 if (day == 0 && (month==1||month-1 == 1 || month-1 == 3 || month-1 == 5 || month-1 == 7 || month-1 == 8 || month-1 == 10 || month-1 == 12)) { day = 31; month--; if (month == 0) { month = 12; year--; }
//小月和2月同理。2月需要考虑闰年和平年。
使用for(;;)进行循环,当计数达到5次后结束循环。
最终可以得到回文日如下:
20211202
20200202
20111102
20100102
20011002
20300302 下一次!
20400402
20500502
20600602
20700702
-
使用SimpleDateFormat和Calendar
//首先获取今天的日期,使用SimpleDateFormat的有参构造 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String format = sdf.format(new Date); //如此获得了字符串类型的今天的日期。格式为:yyyy-MM-dd
使用Calendar类获取明天的日期。
//由于Calendar是一个抽象类,所以我们使用Calendar的子类GregorianCalendar,这里使用多态的思想创建对象。 Calendar calendar = new GregorianCalendar(); //先调用calendar的setTime方法,然后使用add方法。 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Calendar calendar = new GregorianCalendar(); calendar.setTime(new Date()); //偏移量是1,即为当前日期的后一天。 calendar.add(Calendar.DAY_OF_MONTH,1); String date = sdf.format(calendar.getTime());
现在只要更改偏移量,就可以得到不同的日期。
现在只要定义一个变量,作为偏移量。
static int i =1; calendar.add(Calendar.DAY_OF_MONTH,i);
在每次最后对i进行自增即可。
现在得到的String类型的date的格式为yyyy-MM-dd,因此需要0和9相同等。
下面做回文日的判断。
if(date.charAt(0)==date.charAt(9)&&date.charAt(1)==date.charAt(8)&&date.charAt(2)==date.charAt(6)&&date.charAt(3)==date.charAt(5)){ System.out.println(date); count++; }
由此,完整代码如下:
int count=0; int i =1; for (;;) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Calendar calendar = new GregorianCalendar(); calendar.setTime(new Date()); calendar.add(Calendar.DAY_OF_MONTH,i); String date = sdf.format(calendar.getTime()); if(date.charAt(0)==date.charAt(9)&&date.charAt(1)==date.charAt(8)&&date.charAt(2)==date.charAt(6)&&date.charAt(3)==date.charAt(5)){ System.out.println(date); count++; } if(count==5){ break; } i++; }
如果要找再往前的,则将偏移值改为-i。
最终结果如下:
2021-12-02
2020-02-02
2011-11-02
2010-01-02
2001-10-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
-
结语
由此我使用不同学习时段的两种方法计算出了下一次回文日,前者写了将近200行代码,而后者满打满算也只有30行,由此我感悟到了学海无涯。下一次回文日将出现在约8年之后,2030年3月2日。我们这一生也仅仅能经历回文日屈指可数,
正如李永乐老师所说的,珍惜时间,把握今天!

浙公网安备 33010602011771号