问题描述
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 << n
和 n << 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
try
和 catch
是 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 归忆)