【字符串】B034 迴文日期(枚舉(未知錯誤) | 構造法)

一、題目描述

現在,牛牛想知道:在他指定的兩個日期之間(包含這兩個日期本身),有多少個真實存在的日期是迴文的。

一個 8 位數字是迴文的,當且僅當對於所有的 i(1i8)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

二、題解

方法一:枚舉 + 細節

邊界問題:當輸入樣例爲:

10000101
99991231
預期:331
輸出:305

問題出現在方法 valid 中的這段判斷,爲什麼這樣做會錯呢?

if (month == 2) {
	boolean isLeep = year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
	if (isLeep && day != 29 || !isLeep && day != 28)
		return false;
}
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
	static int[] daysInMonth= {0,31,28,31,30,31,30,31,31,30,31,30,31};
	static boolean isPali(String s) {
        int l = 0, r = s.length()-1;
        while (l < r) {
            if (s.charAt(l++) != s.charAt(r--))
                return false;
        }
	    return true;
	}
	private static boolean valid(int date) {
		int year = date / 10000;
		int month = date % 10000 / 100;
		int day = date % 100;
		if (month == 0 || month > 12)
			return false;
		if (day == 0 || month != 2 && day > daysInMonth[month])
			return false;
		if (month == 2) {
			boolean isLeep = year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
			if (isLeep && day != 29 || !isLeep && day != 28)
				return false;
		}
		return true;
	}
    public static void main(String[] args) throws IOException {  
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        BufferedWriter w = new BufferedWriter(new OutputStreamWriter(System.out));
		int begin = sc.nextInt();
		int end = sc.nextInt();
		int count = 0;
		
		for (int i = begin; i <= end; i++) {
			if (valid(i) && isPali(i+"")) 
				count++;
		}
		System.out.println(count);
    }
}

更正:把 2 月份的邏輯改爲如下代碼,則得到一個 AC

if (month == 2) {
	int isLeep = year % 4 == 0 && year % 100 != 0 || year%400 == 0 ? 1 : 0;
	if (day > isLeep + 28)
	    return false;
}

複雜度分析

  • 時間複雜度:O(n2)O(n^2),數據強一點容易 TLE
  • 空間複雜度:O(1)O(1)

方法二:構造迴文日期

由於迴文日期是 8 位,前 4 位一定和後 4 位鏡像對稱相同。所以枚舉前四位即可。

import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
	static int[] daysInMonth= {0,31,28,31,30,31,30,31,31,30,31,30,31};
	private static boolean valid(int date) {
		int year = date / 10000;
		int month = date % 10000 / 100;
		int day = date % 100;
		if (month == 0 || month > 12)
			return false;
		if (day == 0 || month != 2 && day > daysInMonth[month])
			return false;
		if (month == 2) {
        	int isLeep = year % 4 == 0 && year % 100 != 0 || year%400 == 0 ? 1 : 0;
        	if (day > isLeep + 28)
        	    return false;
        }
		return true;
	}
    public static void main(String[] args) throws IOException {  
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        BufferedWriter w = new BufferedWriter(new OutputStreamWriter(System.out));
		int begin = sc.nextInt();
		int end = sc.nextInt();
		int count = 0;
		
		for (int i = 1000; i <= 9999; i++) {
			int date = i, t = i;
			while (t != 0){
				date = date * 10 + t % 10;
				t /= 10;
			}
			if (begin <= date && date <= end && valid(date)) {
				count++;
			}
		}
		System.out.println(count);
    }
}

複雜度分析

  • 時間複雜度:O(104)O(10^4)
  • 空間複雜度:O(1)O(1)

附:fun story

  • 普通閏年:公曆年份是 4 的倍數的,且不是 100 的倍數,爲閏年。
  • 世紀閏年:公曆年份是整百數的,必須是 400 的倍數纔是世紀閏年
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章