java pta三次题目集的总结

发布时间 2023-03-26 20:13:52作者: 曦凪

第一次题目集

第一次题目集相对比较简单,整体考验的是我们循环和if else逻辑判断还有一定的算法基础,比如最后一题:

7-12 列出最简真分数序列*

题目描述:

  按递增顺序依次列出所有分母为N(10 <= N <= 40),分子小于N的最简分数。

分析:

  首先从题目可以看出来,只要分子不能被N整除就可以,那么可以从1开始一直到N,依次判断每个数能不能被N整除,这里可以使用递归判断:

private static int gcd(int a, int b) {
  if (b == 0) {
    return a;
  }
  return gcd(b, a % b);
}

不断求b除模除a模除b,直到a模除b等于0

第二次题目集

这次题目集难度就上升了,逻辑判断更多了,而且还考验我们对类的设计,数据的处理

倒数第二题:

题目描述:

  输入三角形三条边,判断该三角形为什么类型的三角形。

分析:

  这题目看起来还是挺简单的,根据三条边的长度即可判断,但是有几个难点,就是直角三角形,我们都知道a的平方加b的平方等于c的平方就是直角三角形,但是当我们使用math.pow()这个方法去判断的时候会出错,这是因为精度问题,会存在误差,因此我们做题的时候需要注意,当这个误差小于多少时,就认为他们是直角三角形

import java.math.BigDecimal;
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
double bian1 = scanner.nextDouble();
double bian2 = scanner.nextDouble();
double bian3 = scanner.nextDouble();
if (bian1 < 1 || bian1 > 200 || bian2 < 1 || bian2 > 200 || bian3 < 1 || bian3 > 200) {
System.out.println("Wrong Format");
} else if (!(bian1 + bian2 > bian3 && bian1 + bian3 > bian2 && bian2 + bian3 > bian1)) {
System.out.println("Not a triangle");
} else if (bian1 == bian2 && bian1 == bian3) {
System.out.println("Equilateral triangle");
} else if (bian1 == bian2 || bian2 == bian3 || bian1 == bian3) {
if (Math.pow(bian1, 2) + Math.pow(bian2, 2) == Math.round(Math.pow(bian3, 2))
|| Math.pow(bian2, 2) + Math.pow(bian3, 2) == Math.round(Math.pow(bian3, 2))
|| Math.pow(bian1, 2) + Math.pow(bian3, 2) == Math.round(Math.pow(bian3, 2))) {
System.out.println("Isosceles right-angled triangle");
} else {
System.out.println("Isosceles triangle");
}
} else if (Math.pow(bian1, 2) + Math.pow(bian2, 2) == Math.pow(bian3, 2)
|| Math.pow(bian2, 2) + Math.pow(bian3, 2) == Math.pow(bian1, 2)
|| Math.pow(bian1, 2) + Math.pow(bian3, 2) == Math.pow(bian2, 2)) {
System.out.println("Right-angled triangle");
} else {
System.out.println("General triangle");
}
}
}

这里直接简单粗暴的进行判断了,因为底层逻辑不难

最后一题:

题目描述:

  输入年月日的值(均为整型数),输出该日期的下一天。 其中:年份的合法取值范围为[1820,2020] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。

分析:

  这题逻辑比较简单,只需要考虑闰年的问题就可以了,因为每个月的天数都是固定的,接下来再判断下一天是否是下一个月,或者是下一年就好了,如果不是让天数加1直接输出就好了

代码:

import java.util.Scanner;

public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int year = scanner.nextInt();
int month = scanner.nextInt();
int day = scanner.nextInt();
nextDate(year, month, day);
}

public static boolean isLeapYear(int year) {
if (year % 4 == 0) {
if (year % 100 == 0) {
return year % 400 == 0;
} else {
return true;
}
} else {
return false;
}
}

public static boolean checkInputValidity(int year,int month,int day) {
if (year < 1820 || year > 2020 || month < 1 || month > 12 || day < 1 || day > 31) {
return false;
} else {
if (month == 2 || month == 4 || month == 6 || month == 9 || month == 11) {
if (month == 2) {
if (isLeapYear(year)) {
return day <= 29;
} else {
return day <= 28;
}
} else {
return day <= 30;
}
}
return true;
}
}

public static void nextDate(int year,int month,int day) {
if (checkInputValidity(year, month, day)) {
check(year, month, day, isLeapYear(year));
} else {
System.out.println("Wrong Format");
}
}

public static void check(int year, int month, int day, boolean isYear) {
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month ==12) {
if (day == 31) {
if (month == 12) {
day = 1;
month = 1;
year++;
System.out.println("Next date is:" + year + "-" + month + "-" + day);
} else {
month++;
day = 1;
System.out.println("Next date is:" + year + "-" + month + "-" + day);
}
} else {
day++;
System.out.println("Next date is:" + year + "-" + month + "-" + day);
}
} else {
if (month == 2) {
if (day == (isYear ? 29 : 28)) {
day = 1;
month++;
System.out.println("Next date is:" + year + "-" + month + "-" + day);
} else {
day++;
System.out.println("Next date is:" + year + "-" + month + "-" + day);
}
} else {
if (day == 30) {
day = 1;
month++;
System.out.println("Next date is:" + year + "-" + month + "-" + day);
} else {
day++;
System.out.println("Next date is:" + year + "-" + month + "-" + day);
}
}
}
}
}

第三次题目集

7-3 定义日期类

 题目描述:
  定义一个类Date,包含三个私有属性年(year)、月(month)、日(day),均为整型数,其中:年份的合法取值范围为[1900,2000] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。
分析:
  定义一个类首先想到的属性,对应的getter,setter方法,然后就是这个类的构造函数,因为需要考虑到多种情况,最好是多定义几个构造函数,然后就是类的成员方法,一个日期类首先应该有的判断一个日期是否合法,这个还是比较容易的:

public static boolean check(int year, int month, int day) {
if (year < 1900 || year > 2000 || month < 1 || month > 12 || day < 1 || day > 31) {
return false;
} else {
if (isRunNian(year)) {
if (month == 2) {
return day <= 29;
}
} else {
if (month == 2) {
return day <= 28;
}
}
if (month == 4 || month == 6 || month == 9 || month == 11) {
return day <= 30;
}
return true;
}
}

这里是有问题的,因为在这里我使用了很多常量,这些常量不应该直接出现在方法里面,最好是用一个数组或者是集合存储起来,我这样写是更直观

然后就是判断闰年了和求下一天了,求下一天上面已经说明了,闰年判断比较简单,这里不再说明

7-4 日期类设计

题目描述:

  

参考题目3和日期相关的程序,设计一个类DateUtil,该类有三个私有属性year、month、day(均为整型数),其中,year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 除了创建该类的构造方法、属性的getter及setter方法外,需要编写如下方法:

public boolean checkInputValidity();//检测输入的年、月、日是否合法
public boolean isLeapYear(int year);//判断year是否为闰年
public DateUtil getNextNDays(int n);//取得year-month-day的下n天日期
public DateUtil getPreviousNDays(int n);//取得year-month-day的前n天日期
public boolean compareDates(DateUtil date);//比较当前日期与date的大小(先后)
public boolean equalTwoDates(DateUtil date);//判断两个日期是否相等
public int getDaysofDates(DateUtil date);//求当前日期与date之间相差的天数
public String showDate();//以“year-month-day”格式返回日期值
 

应用程序共测试三个功能:

  1. 求下n天
  2. 求前n天
  3. 求两个日期相差的天数

分析:

   既然求下一天会了,那么求下n天就不难了,就是让当前的日期的天数不断+1,一直加到n,前n天就是直接-1,直到n,这里可以使用递归做,也可以使用while循环做,但是这样时间复杂度是o(n),有复杂度更低的方法,就是让日期的day变量直接加上n,再根据day,对year和month进行增加或者减少,但是这样逻辑会更复杂,也可以像java的日期类一样,以某一个时间点为基准进行计算

代码:

  我这里采用的是最后一种写法,以1800年1月1日为基准进行计算,但是我写完才发现虽然效率高但是复杂度高了挺多,我是先将年月转换成天数,再对天数进行操作

public int getDay(DateUtil date) {
int sum = 0;
int count = 0;
for (int i = 1800; i < date.getYear(); i++) {
if (isLeapYear(i)) {
count++;
}
}
sum += (date.getYear() - 1800) * 365 + count;
switch (date.getMonth()) {
case 1:
sum += date.getDay();
break;
case 2:
sum += date.getDay() + 31;
break;
case 3:
sum += date.getDay() + 31 + (isLeapYear(date.getYear()) ? 29 : 28);
break;
case 4:
sum += date.getDay() + (isLeapYear(date.getYear()) ? 29 : 28) + 31 * 2;
break;
case 5:
sum += date.getDay() + (isLeapYear(date.getYear()) ? 29 : 28) + 31 * 2 + 30;
break;
case 6:
sum += date.getDay() + (isLeapYear(date.getYear()) ? 29 : 28) + 31 * 3 + 30;
break;
case 7:
sum += date.getDay() + (isLeapYear(date.getYear()) ? 29 : 28) + 31 * 3 + 30 * 2;
break;
case 8:
sum += date.getDay() + (isLeapYear(date.getYear()) ? 29 : 28) + 31 * 4 + 30 * 2;
break;
case 9:
sum += date.getDay() + (isLeapYear(date.getYear()) ? 29 : 28) + 31 * 5 + 30 * 2;
break;
case 10:
sum += date.getDay() + (isLeapYear(date.getYear()) ? 29 : 28) + 31 * 5 + 30 * 3;
break;
case 11:
sum += date.getDay() + (isLeapYear(date.getYear()) ? 29 : 28) + 31 * 6 + 30 * 3;
break;
case 12:
sum += date.getDay() + (isLeapYear(date.getYear()) ? 29 : 28) + 31 * 6 + 30 * 4;
break;
}
return sum + 1;
}

这里是求两个日期相差的天数,我在这里犯了一个错,不难发现我这里用了一个switch判断了好多次,而在实际的代码中我们应该减少这种逻辑判断,而且最致命的是,如果以1800年为基准,那么当n过大的时候,就会出问题

 

 

 

 

所以这里不推荐使用这种方式,最好是使用上述的第一种方法,使用递归或者是循环

这里以求前n天为例子:

while(!day1.Equlas(day2)) {

  day1.getNextDay(1);

}

因为在getNextDay()方法里面操作的是this对象,所以可以直接使用day1.getNextDay(1),至于Equlas()是判断两个日期是否相等的方法,这个比较简单,只需要判断年月日是否相等就好了

总结:

题量和难度:

  题量不是很大,难度也属于简单类型,都是做几个小时就能做完的

知识点涉及:

  这三次题目集主要考验了我们的基础逻辑判断if else, while for等循环语句,还有就是对类的设计,数据的处理,调试的用法,还有就是对错误的分析

反思:

  这三次题目集整体来讲难度偏简单,但是里面有许多细节,比如数据处理这一块,我们在使用浮点数的时候,一定要考虑精度和误差的问题,我因为这个问题踩了好几次坑,其次是我们在做题的时候,应该先试着把题目做出来,而不是一开始就考虑最佳的算法,比如题目集三的最后一题,我一开始就考虑的是怎么快速的算出来,导致浪费了许多的时间,我们应该先做出来,然后再在原来的基础上进行改进

学习:

  这三次题目集让我对类的设计更熟练了,以及做题的思路和习惯得到了一些正确的矫正,还接触到了许多算法,比如辗转相除求最大公约数的那个,此外对java的数据结构又更加熟悉了,比如String的一些方法如subString,indexOf,split,还有Arrays的方法如sort,sum,min等等