蓝桥回文日期

Posted Mr YiRan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥回文日期相关的知识,希望对你有一定的参考价值。


示例
输入

20200202

输出

20211202
21211212

在java中有一个类是LocalDate
LocalDate 是 Java8中新增的日期类,采用了系统的默认时区。可以方便的处理 日期对象 的 年、月、日 信息。有这个类在解决日期类问题比较方便。
下面常用的几个常用API

1.创建日期对象
 获取当前日期对象
LocalDate.now() : 返回默认时区下的、系统始终下的 当前日期
2.获取日期对象的 年、月、日 信息
getYear() : 获取年分信息
getMonth() : 获取月份信息(枚举类型)
getMonthValue() : 获取月份的数字(数值类型)
getDayOfMonth() : 获取日期信息
getDayOfWeek() : 获取星期几 (枚举类型)
getDayOfYear() : 获取这一年的第几天
 3.指定 日期对象的属性
withYear(int) : 设置年
withMonth(int) : 设置月
withDayOfMonth(int) : 设置日
withDayOfYear(int) : 设置这一年的第几天
 with(TemporalAdjuster) : 时间调整器,更方便的调整
 
 4.加上 或者 减去 年、月、日、周
plusYears(long) : 加几年
plusMonths(long) : 加几个月
plusDays(long) : 加几天
plusWeeks(long) : 加几个星期
minusYears(long) : 减几年
minusMonths(long) : 减几个月
minusDays(long) : 减几天
minusWeeks(long) : 减几个星期
import java.time.LocalDate;
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main 


    public static void main(String[] args) 
        Scanner scanner=new Scanner(System.in);
        String N = scanner.next();
        //System.out.println(N);
        int year=Integer.parseInt(N.substring(0,4));
        int month=Integer.parseInt(N.substring(4,6));
        int day = Integer.parseInt(N.substring(6, 8));
        LocalDate date = LocalDate.now();//通过LocalDate这个类实现日期操作
        //修改当前年月日
        date=date.withYear(year);
        date=date.withMonth(month);
        date=date.withDayOfMonth(day);
        //2020-02-02
        //System.out.println(date);
        //分割成20200202

        //System.out.println(s);
        String a="";//第一个回文日期
        String b="";//第二个ABABBABA型回文日期
        boolean isFind=false;
        while(true)
            //一直往后找
            date=date.plusDays(1);
            String s= date.toString().replace("-","");
            if(isHuiWen(s))
                //说明是回文数
                if(!isFind)
                    a=s;
                    isFind=true;
                
                if(isABABBABA(s))
                    //说明是ABABBABA类型的
                  b=s;
                  break;
                
            

        
        System.out.println(a);
        System.out.println(b);
        scanner.close();

    

    private static boolean isABABBABA(String s) 
        //判断ABABBABA
        if(s.charAt(0)==s.charAt(7)&&s.charAt(1)==s.charAt(6)&&s.charAt(2)==s.charAt(5)
        &&s.charAt(3)==s.charAt(4)&&s.charAt(0)==s.charAt(2)&&s.charAt(1)==s.charAt(3)
        )
        
            return true;
        

        return false;
    

    private static boolean isHuiWen(String s) 

       int mid=s.length()/2;
       int r=s.length()-1;
//        System.out.println("mid"+mid);
//        System.out.println("r"+r);
//        System.out.println("进来isHuiWen"+s);
        for(int i=0;i<mid;i++)
//            System.out.println("s.charAt(i)"+s.charAt(i));
//            System.out.println("s.charAt(r)"+s.charAt(r));
            if(s.charAt(i)!=s.charAt(r))
                return false;
            
            r--;
        
        return true;
    



不使用LocalDate类的另一种方法
1.首先要满足回文的形式,即ABCDDCBA,对于回文的判断用数组会方便许多。

2.ABABBABA型:此处也可以使用数组判断是否是回文型。

3.要满足日期的格式。

暴力求解思路:预先存储好各个月份的天数。需要三个判断方法:

a.判断是否是闰年,如果是,则将存储的二月份的天数改为29

b.判断是否是回文型

c.判断是否是ABAB型

通过三重for循环来寻找下一次回文日期。巧妙运用for循环的执行顺序就可以实现从当前日期往后开始寻找。先增加天数,天数满了增加月份,月份也满了增加年份。要注意增加月份和年份时对应地要初始化天数和月份。通过两个Boolean值来判断是否找到我们的目标日期,当两个Boolean值都为true时说明都找到了我们的目标日期,可以退出循环了。

import java.util.*;
class Main
    static boolean IsRun(int y) 
        if(y%400==0||(y%4==0&&y%100!=0)) return true;
        return false;
    
    static boolean ABBA(String Str)//判断回文日期
        char []str=Str.toCharArray();
        if(str[0]==str[7]&&str[1]==str[6]&&str[2]==str[5]&&str[3]==str[4]) return true;
        return false;
    
    static boolean ABAB(String Str) //判断ABBA型
        char []str=Str.toCharArray();
        if(str[0]==str[2]&&str[2]==str[5]&&str[5]==str[7]&&str[1]==str[3]&&str[3]==str[4]&&str[4]==str[6]&&str[0]!=str[1]) 
            return true;
        return false;
    
    public static void main(String args[]) 
        int monthes[]=0,31,28,31,30,31,30,31,31,30,31,30,31;
        Scanner in=new Scanner(System.in);
        String time=in.next();
        Integer tt=Integer.parseInt(time);
        int year=tt/10000;
        int month=tt%10000/100;
        int day=tt%100+1;
        int n;
        int []ans=new int[2];
        boolean flag1=false,flag2=false;
        if(IsRun(year)) monthes[2]=29;
        for(int i=year;i<=9999;i++,month=1,day=1) //巧妙运用for循环的顺序,可以实现从当前日期开始往后寻找
            for(int j=month;j<=12;j++,day=1) 
                for(int k=day;k<=monthes[j];k++) 
                    n=i*10000+j*100+k;
 
                    String Str=String.valueOf(n);
                    if(ABBA(Str)&&flag1==false) 
                        String str1=Str;
                        flag1=true;
                        ans[0]=n;
                    
                    if(ABAB(Str)&&flag2==false) 
                        String str2=Str;
                        flag2=true;
                        ans[1]=n;
                    
                    if(flag1==true&&flag2==true) break;
                
            
        
        System.out.println(ans[0]);
        System.out.println(ans[1]);
    

回文日期 (蓝桥云) JAVA

目录

题目描述:

2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd”
的格式写成一个 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。

有人表示 20200202 是 “千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即
2021 年 12 月 2 日。

也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。对此小明也不认同,因为大约 100
年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。算不上 “千年一遇”,顶多算
“千年两遇”。

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

输入描述:

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

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

输出描述:

输出两行,每行 1 个八位数。第一行表示下一个回文日期,第二行表示下一个 ABABBABA 型的回文日期。

输入输出样例:

输入

20200202

输出

20211202
21211212


统领:

第一次参加蓝桥杯,所以今天才知道蓝桥杯采用oi机制,即提交后没有任何反馈,这给我的冲击很大,因为我平常写完代码,第一时间是去平台测试,根据平台反馈,找错误原因,而蓝桥杯的赛制,直接让我的这个习惯成为了最大破绽。失去了通过平台找错因的手段,让我备受打击,抱着从头再来的想法。我在蓝桥云找了一道适合我水平的题目,试试一遍能得多少分。
好在这一次侥幸能够全部AC给我带来了一丝希望,以下是通过题目总结我的心得。


本题完整代码:

import java.util.*;
public class Main 
   public static  int month[] = 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31;
   public static void main(String[] args) 
	   Scanner sc = new Scanner(System.in);
       int n = sc.nextInt();
       int yy = n / 10000;
       //System.out.println(yy);
       while(true) 
    	   if(check(yy)) 
    		   StringBuffer s = new StringBuffer(String.valueOf(yy));
    		   String s1 = String.valueOf(yy);
    		   s1 = s1 + s.reverse();
    		   if(Integer.parseInt(s1) > n) 
    		     System.out.println(s1);
    		     break;
    		   
    	   
    	   yy  = yy + 1;
       
       int YY = n / 1000000;
       while(true) 
    	   if(check_y(YY)) 
    		   StringBuffer s2 = new StringBuffer(String.valueOf(YY * 100 + YY));
    		   String s3 = String.valueOf(YY * 100 + YY) + s2.reverse();
    		   if(Integer.parseInt(s3) > n) 
    		     System.out.print(s3);
    		     break;
    		   
    	   
    	   YY = YY + 1;
       
   
   public static boolean check_y(int m) 
	   int yy = m * 100 + m;
	   if(yy % 4 == 0 && yy % 100 != 0 || yy % 400 == 0) 
		   month[2] = 29;
	   
	   else month[2] = 28;
	   StringBuffer s = new StringBuffer(String.valueOf(yy));
	   String s1 = "" + s.reverse();
	   int mm = Integer.parseInt(s1.substring(0, 2));
	   int dd = Integer.parseInt(s1.substring(2, 4));
	   //System.out.println(month[2]);
	   if(mm <= 0 || mm > 12) return false;
	   if(month[mm] < dd) return false;
	   return true;
   
   public static boolean check(int n) 
	   int yy = n;
	   if(yy % 4 == 0 && yy % 100 != 0 || yy % 400 == 0) 
		   month[2] = 29;
	   
	   StringBuffer s = new StringBuffer(String.valueOf(yy));
	   String s1 = "" + s.reverse();
	   int mm = Integer.parseInt(s1.substring(0, 2));
	   int dd = Integer.parseInt(s1.substring(2, 4));
	   //System.out.println(month[2]);
	   if(mm <= 0 || mm > 12) return false;
	   if(month[mm] < dd) return false;
	   return true;
   


心得:

蓝桥杯是提交没有反馈的,所以我们得细心细心再细心,不要图快,急着把做后面的题。我导师跟我说一个大哥,去年参赛国二,卷了一年再考蓝桥杯只得了省三。问题不在于他题不会,他是所有题都做了。可想而知,他做的题可能只能通过题目给的样例,而样例又不算分数。所以为了能稳定发挥吧,我对自己的建议是:

1.反复斟酌题目要求:

如果你有一道题是会做的,程序也写出来了,那就要务必保证其能对尽可能多的测试点,题目一定要多读几遍,就拿上述题目来举例子,题目要求输出该日期之后的下一个回文日期,假若你没注意到这一点,那么当N = 20201221时,你的程序输出的可能就是20200202这个输出显然不是正确答案

2.小心谨慎步步为营,多反问:

首先我们应该问自己所有的八位回文数字串都行么?

显然回文日期的月份和天数都得合法才行,即月份应在[0, 12], 天数应该在当月的范围内

再思考到当月的天数范围,我们就意识到了,还得判断这个年是闰年还是平年,这样二月的天数范围我们就明确了

考虑到上述问题后,我们的正确率就提高了,然后就是构思去实现一个check函数判断我们的回文日期是否合法:

public static boolean check(int n) 
	   int yy = n;
	   if(yy % 4 == 0 && yy % 100 != 0 || yy % 400 == 0) 
		   month[2] = 29;
	   
	   StringBuffer s = new StringBuffer(String.valueOf(yy));
	   String s1 = "" + s.reverse();
	   int mm = Integer.parseInt(s1.substring(0, 2));
	   int dd = Integer.parseInt(s1.substring(2, 4));
	   //System.out.println(month[2]);
	   if(mm <= 0 || mm > 12) return false;
	   if(month[mm] < dd) return false;
	   return true;
   

写完check后我们不要急着走,我们应该及时检查这个check函数是否正确,多想几个样例测试一下,确保无误后再继续进行。这样如果整个代码出现问题,至少我们能排除check代码的问题,这就是步步为营。

3.调节代码之间的关系:

那本题为例输出有两个一个是回文日期,一个是ABABBABA型回文,这里就存在一个问题,如果前者输出回文日期,判断的年份刚好是闰年,我们修改了month[2] = 29而下一个这个ABABBABA型日期刚好是平年,这里就容易出问题了。

所以为了解决这个问题,实现ABABBABA型的代码就需要调整了。

 if(yy % 4 == 0 && yy % 100 != 0 || yy % 400 == 0) 
		   month[2] = 29;
	   
	   else month[2] = 28;

如上图我添加了一个else语句,这样代码的正确率又会提高。


总结:

要想用代码去实现一道题目,我们需要把这其中很难多问题分块解决,并用代码去解决。个人亲身体会,去解决这些块问题,要比分析边界要花费的时间更多。所以如果我们写出代码后直接潦草提交,就有可能会因为其中的细节没考虑到而功亏一篑。既然我们已经投入了这么多时间去用编程解决这道题,那么为何不愿多花点时间找出可能的边界,得到更多的分数?显然有时候是我太贪心了,分不清西瓜和芝麻。

想想也是没必要抱怨,能够自己排除bug,分析可能的错因,写出优质代码,让用户有更好的体验。何尝不是一个合格程序员该具备的?😄

利用余下的时间我会继续依靠采用这种一遍过的模式做题,适应oi赛制。

以上是关于蓝桥回文日期的主要内容,如果未能解决你的问题,请参考以下文章

java 蓝桥杯 算法基础 回文串

小学生蓝桥杯Python闯关 | 回文日期

蓝桥杯省赛题解2015-2022

Java蓝桥杯--基础练习 回文数

Java蓝桥杯--基础练习特殊回文数

[蓝桥杯Python]算法练习算法基础算法训练算法模板(持续更新)