【蓝桥杯3492】日期统计(子序列&迭代&暴力&枚举&java&String类&日期类&集合类)

问题描述

5 6 8 6 9 1 6 1 2 4 9 1 9 8 2 3 6 4 7 7 5 9 5 0 3 8 7 5 8 1 5 8 6 1 8 3 0 3 7 9 2
7 0 5 8 8 5 7 0 9 9 1 9 4 4 6 8 6 3 3 8 5 1 6 3 4 6 7 0 7 8 2 7 6 8 9 5 6 5 6 1 4 0 1
0 0 9 4 8 0 9 1 2 8 5 0 2 5 3 3

输入输出

解题思路

先手动排除一些,因为要获取2023后才算有效,排除后的数组如下:

{ 3, 8, 5, 1, 6, 3, 4, 6, 7, 0, 7, 8, 2, 7, 6, 8, 9, 5, 6, 5, 6, 1, 4, 0, 1, 0, 0, 9, 4, 8, 0, 9, 1, 2, 8, 5, 0, 2, 5, 3, 3 }

直接减少了一大半,大大缩减了运行时间。

下方有一个失败代码和一个AC代码,代码后面都有解释。

失败代码(运行时间太长)

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
	static String year = "2023";
	static long ans = 0;
	static long[] zu = { 3, 8, 5, 1, 6, 3, 4, 6, 7, 0, 7, 8, 2, 7, 6, 8, 9, 5, 6, 5, 6, 1, 4, 0, 1, 0, 0, 9, 4, 8, 0, 9,
			1, 2, 8, 5, 0, 2, 5, 3, 3 };
	static int len = zu.length;
	static char[] zuStr = new char[len];
	static long minLen = 2, maxLen = 4;

	public static void main(String[] args) {

		for (int i = 0; i < len; i++) {
			zuStr[i] = (char) (zu[i] + '0');
		}

		long maxI = (long) Math.pow(2, len);
		for (long i = 1; i < maxI; i++) {

			/*
			 * 错误部分 String str = ""; for (int j = 0; j < len; j++) { if ((i & (1 << j)) > 0)
			 * { str += zuStr[j]; } }
			 */
			String iBin = Long.toBinaryString(i);
			String str = "";
			for (int j = 0; j < iBin.length(); j++) {
				if (iBin.charAt(j) == '1') {
					str += zuStr[j];
				}
			}
//				System.out.println(year + str);
//			str = new StringBuilder(str).reverse().toString();

			long strLen = str.length();
			String strFinal;
			if (strLen == 4) {
				strFinal = year + str;
//				System.out.println(strFinal);
				isValidDate(str);
			}
			/*
			 * if (strLen >= 2 && strLen <= 4) { switch (strLen) { case 2: strFinal = year +
			 * '0' + str.charAt(0) + '0' + str.charAt(1); isValidDate(strFinal); break; case
			 * 3: strFinal = year + '0' + str.charAt(0) + str.substring(1, 3);
			 * isValidDate(strFinal); strFinal = year + str.substring(0, 2) + '0' +
			 * str.charAt(2); isValidDate(strFinal); break; case 4: strFinal = year + str;
			 * isValidDate(strFinal); break; } }
			 */
		}

		System.out.println(ans);
	}

	static void isValidDate(String dateString) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyymmdd");
		sdf.setLenient(false);
		try {
			Date date = sdf.parse(dateString);
			ans++;
		} catch (ParseException e) {
		}
	}
}

 这个思路是想着用二进制形式的数去模拟取位,1则取该位,0则不取,结果for循环的i可以达到2的四十多次方.......

另外还有一个错误:yyyymmdd。应该是yyyyMMdd

还要注意一点:要设置集合!!!不然会重复计数!

AC代码

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

public class Main {

	public static void main(String[] args) {
		System.out.println(235);
		/*
		// 固定年份
		String year = "2023";
		// 记录合法日期的数量
		int ans = 0;
		// 给定的数字数组
		int[] zu = { 3, 8, 5, 1, 6, 3, 4, 6, 7, 0, 7, 8, 2, 7, 6, 8, 9, 5, 6, 5, 6, 1, 4, 0, 1, 0, 0, 9, 4, 8, 0, 9, 1,
				2, 8, 5, 0, 2, 5, 3, 3 };
		// 数组长度
		int len = zu.length;
		// 数组转换为字符数组
		char[] zuStr = new char[len];
		// 将数字数组转换为字符数组
		for (int i = 0; i < len; i++) {
			zuStr[i] = (char) (zu[i] + '0');
		}

		// 使用Set保存已经生成的日期,避免重复计数
		Set<String> set = new HashSet<>();

		// 四重循环生成长度为4的子序列
		for (int i = 0; i < len; i++) {
			String str = String.valueOf(zuStr[i]);
			for (int j = i + 1; j < len; j++) {
				str += String.valueOf(zuStr[j]);
				for (int k = j + 1; k < len; k++) {
					str += String.valueOf(zuStr[k]);
					for (int l = k + 1; l < len; l++) {
						str += String.valueOf(zuStr[l]);

						// 2023 + 长度为4的子序列 得到一个日期
						String date = year + str;

						// 判断日期是否合法
						if (isValidDate(date)) {
							// 如果日期合法且不在Set中,增加计数并添加到Set中
							if (!set.contains(date)) {
								ans++;
								set.add(date);
							}
						}
						// 每次迭代后去掉末尾的字符
						str = str.substring(0, str.length() - 1);
					}
					// 每次迭代后去掉末尾的字符
					str = str.substring(0, str.length() - 1);
				}
				// 每次迭代后去掉末尾的字符
				str = str.substring(0, str.length() - 1);
			}
			// 每次迭代后去掉末尾的字符
			str = str.substring(0, str.length() - 1);
		}

		System.out.println(ans);
	}

	// 判断日期是否合法的方法
	static boolean isValidDate(String dateString) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		sdf.setLenient(false);
		try {
			Date date = sdf.parse(dateString);
			return true;
		} catch (Exception e) {
			return false;
		}
		*/
	}
}

这个代码的思路是用4层for循环找到剩下的四位数,加上2023后再进行判断日期是否合法。

其实可以用dfs替换4层for,不过看在复杂度不大的情况下就没必要再花时间去构思了。

同时用了集合确保不会对相同的日期进行重复计数。

最后要直接输出结果,不然提交后会超时。

相关知识 

1 << n 和 n << 1

1 << nn << 1 是位运算中的左移操作,它们的结果是不同的。

  • 1 << n 表示将数字1左移 n 位,相当于 2 的 n 次方。
  • n << 1 表示将数字 n 左移 1 位,相当于 n 乘以 2。

举个例子,假设 n 等于 3:

  • 1 << 3 结果为 8,因为 2 的 3 次方等于 8。
  • 3 << 1 结果为 6,因为 3 乘以 2 等于 6。

String变量和字符数组转换

public class Main {
    public static void main(String[] args) {
        // 字符串转换为字符数组
        String str = "Hello, World!";
        char[] charArray = str.toCharArray();

        System.out.println("Original String: " + str);
        System.out.print("Character Array: ");
        for (char ch : charArray) {
            System.out.print(ch + " ");
        }
        System.out.println();

        // 字符数组转换为字符串
        char[] newCharArray = {'H', 'e', 'l', 'l', 'o'};
        String newString = new String(newCharArray);

        System.out.println("New Character Array: " + newString);
    }
}

String变量反转

public class Main {
        public static void main(String[] args) {
            String originalStr = "Hello, World!";

            // 使用 StringBuilder 反转字符串变量
            StringBuilder reversedStrBuilder = new StringBuilder(originalStr);
            reversedStrBuilder.reverse();
            String reversedStr = reversedStrBuilder.toString();

            //也可以一条语句解决
            String str = "123456";
            str = new StringBuilder(str).reverse().toString();

            System.out.println("Original String: " + originalStr);
            System.out.println("Reversed String: " + reversedStr);
        }
    }

String变量之间部分赋值 

public class Main {
    public static void main(String[] args) {
        String originalString = "Hello, World!";
        System.out.println("Original String: " + originalString);

        // 使用 substring 进行部分赋值
        // 包含 0 但是不包含 5
        String modifiedString = originalString.substring(0, 5) + " Java!";
        System.out.println("Modified String: " + modifiedString);
    }
}

判断日期是否合法

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
    public static void main(String[] args) {
        String d1 = "20231206";
        System.out.println(isValidDate(d1));

        String d2 = "20231266";
        System.out.println(isValidDate(d2));
    }

    /**
     * 使用 SimpleDateFormat 检查日期是否合法
     *
     * @param dateString 要检查的日期字符串
     * @return 如果日期合法则返回 true,否则返回 false
     */
    static boolean isValidDate(String dateString) {
        // 创建 SimpleDateFormat 实例,用于日期解析
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

        // 设置为严格解析,不容忍不合法日期
        sdf.setLenient(false);

        try {
            // 尝试解析日期字符串
            Date date = sdf.parse(dateString);
            // 如果解析成功,则日期合法
            return true;
        } catch (ParseException e) {
            // 捕获 ParseException 异常,说明日期不合法
            return false;
        }
    }
}

日期格式模式是由特定字符组成的字符串,每个字符都表示日期或时间的一部分。以下是一些常见的日期格式字符:

  • yyyy:四位年份
  • MM:两位月份
  • dd:两位日期
  • HH:两位小时(24小时制)
  • mm:两位分钟
  • ss:两位秒

非法日期转换为合法日期

import java.util.Calendar;

public class Main {
    public static void main(String[] args) {
        // 创建 Calendar 对象
        Calendar calendar = Calendar.getInstance();

        // 设置宽容度为 true,允许解析和转换非法日期
        // 可以省略,因为默认就是true
        calendar.setLenient(true);

        // 设置日期为一个非法日期
        // Calendar.FEBRUARY代表2月,可以用1替换,因为月份从0开始表示
        calendar.set(2023, Calendar.FEBRUARY, 30);      

        // 获取宽容度
        boolean isLenient = calendar.isLenient();
        System.out.println("Is Lenient: " + isLenient);
        //Is Lenient: true

        // 获取转换后的日期
        // 会将非法日期转换为合法日期
        System.out.println("Date: " + calendar.getTime());
        // Date: Thu Mar 02 14:01:47 CST 2023
    }
}

日期和字符串转换

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date();

        // 格式化日期为字符串
        String formattedDate = sdf.format(date);
        System.out.println(formattedDate);

        // 解析字符串为日期
        String dateString = "2023-11-20 15:30:45";
        try {
            Date parsedDate = sdf.parse(dateString);
            System.out.println(parsedDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }

    }
}

计算代码运行的时间差

public class Main {
    public static void main(String[] args) {
        // 获取代码块运行前的时间戳
        long startTime = System.currentTimeMillis();

        // 获取代码块运行后的时间戳
        long endTime = System.currentTimeMillis();

        // 计算时间差
        long elapsedTime = endTime - startTime;

        // 打印时间差
        System.out.println("代码块运行时间:" + elapsedTime + " 毫秒");
    }
}

 集合Set常用方法

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        // 创建一个 HashSet 对象
        Set<String> fruitSet = new HashSet<>();

        // 添加元素
        fruitSet.add("apple");
        fruitSet.add("banana");
        fruitSet.add("orange");

        // 使用迭代器遍历集合
        System.out.println("Fruits in the set:");
        Iterator<String> iterator = fruitSet.iterator();
        while (iterator.hasNext()) {
            String fruit = iterator.next();
            System.out.println(fruit);
        }

        // 判断元素是否存在
        boolean containsBanana = fruitSet.contains("banana");
        System.out.println("Contains banana: " + containsBanana);

        // 移除元素
        fruitSet.remove("orange");

        // 获取集合大小
        int setSize = fruitSet.size();
        System.out.println("Size of the set: " + setSize);

        // 判断集合是否为空
        boolean isEmpty = fruitSet.isEmpty();
        System.out.println("Is the set empty: " + isEmpty);

        // 清空集合
        fruitSet.clear();

        // 再次判断集合是否为空
        isEmpty = fruitSet.isEmpty();
        System.out.println("Is the set empty after clear: " + isEmpty);
    }
}

try和catch 

trycatch 是 Java 中异常处理的关键字。

  • try: 用于包裹可能抛出异常的代码块。在 try 块中,可以编写有可能引发异常的代码。

  • catch: 用于捕获和处理异常。在 catch 块中,可以编写处理异常的代码。当 try 块中的代码引发异常时,控制流会转到匹配的 catch 块。

public class Main {
    public static void main(String[] args) {
        try {
            // 可能引发异常的代码
            int result = divide(10, 0);
            System.out.println(result);
        } catch (ArithmeticException e) {
            // 处理异常的代码
            System.out.println("除法运算发生错误: " + e.getMessage());
        }
    }

    // 一个简单的除法方法,可能引发除零异常
    private static int divide(int numerator, int denominator) {
        return numerator / denominator;
    }
}

在上述例子中,divide 方法可能引发除零异常。在 try 块中调用这个方法,如果发生异常,控制流会跳转到匹配的 catch 块中进行处理。 

(by 归忆)

猜你喜欢

转载自blog.csdn.net/qq1677852098/article/details/134597333