(1)前言:
前三次pta作业主要考察内容大多在与java语法的考察,让我们快速熟悉初步掌握语法知识,其中涉及到的内容包括一维数组,字符串数组,for循环语句,循环的嵌套使用,String类的使用,if-else的分支控制,基本类型转换等。题量随着作业次数的增加逐渐减少,而难度逐渐升高。
(2)设计与分析:
按递增顺序依次列出所有分母为N(10 <= N <= 40),分子小于N的最简分数。
输入格式:
分母 N。
输出格式:
分数之间用逗号分开(含最末逗号)
输入样例:
10
输出样例:
1/10,3/10,7/10,9/10,
<代码如下>
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
int N,flag=1;
Scanner input=new Scanner(System.in);
N=input.nextInt();
System.out.print("1/"+N+",");
for(int i=2;i<N;i++)//i表示分子
{
for(int j=2;j<=i;j++)//j表示除数
if(i%j==N%j&&i%j==0)
{
flag=0;
break;
}
if(flag==0)
{
flag=1;
continue;
}
else System.out.print(i+"/"+N+",");
}
}
}
题目主要目标为将指定分母的最简分数输出并且保证该数小于1。
为实现该目标,运用两个for循环,首先用一层for循环保证分子部分不会大于分母,再用一层循环对分子分母同时进行取余运算,在判断该分数为最简分式后再进行输出,在解决了如何求出最简分式的算法后,该题目的大致问题便基本解决
定义一个类Date,包含三个私有属性年(year)、月(month)、日(day),均为整型数,其中:年份的合法取值范围为[1900,2000] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。
注意:不允许使用Java中和日期相关的类和方法,否则按0分处理。
要求:Date类结构如下图所示:
输入格式:
在一行内输入年月日的值,均为整型数,可以用一到多个空格或回车分隔。
输出格式:
- 当输入数据非法及输入日期不存在时,输出“Date Format is Wrong”;
- 当输入日期合法,输出下一天,格式如下:Next day is:年-月-日
输入样例1:
在这里给出一组输入。例如:
1912 12 25
输出样例1:
在这里给出相应的输出。例如:
Next day is:1912-12-26
输入样例2:
在这里给出一组输入。例如:
2001 2 30
输出样例2:
在这里给出相应的输出。例如:
Date Format is Wrong
<代码如下>
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int year,month,day;
Scanner input = new Scanner(System.in);
year = input.nextInt();
month = input.nextInt();
day = input.nextInt();
Data data = new Data(year, month, day);
if (data.checklnputValidity()) {
data.getNextDate();
}
else
System.out.print("Date Format is Wrong");
}
}
class Data {
private int year;
private int month;
private int day;
int[] mon_maxnum = {0,31,28,31,30,31,30,31,31,30,31,30,31};
Data(){
}
Data(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}
int getYear() {
return year;
}
void setyear(int year) {
this.year = year;
}
int getMonth() {
return month;
}
void setmonth(int month) {
this.month = month;
}
int getDay() {
return day;
}
void setDay(int day) {
this.day = day;
}
boolean isLeapYear(int year) {
if (year % 400 == 0 || year % 4 == 0 && year % 100 != 0)
return true;
else
return false;
}
boolean checklnputValidity() {
if(month > 0 && month <=12)
{
if (mon_maxnum[month] >= day && month != 2 && year >= 1900 && year <= 2000 && day >=1)
return true;
else if (isLeapYear(year) && month == 2 && day <= 29 && day > 0)
return true;
else if (!isLeapYear(year) && month == 2 && day <= 28 && day > 0)
return true;
else
return false;
}
else
return false;
}
void getNextDate() {
if (this.month != 2 && this.month != 12 && this.day != mon_maxnum[month]) {
this.day = day + 1;
System.out.print("Next day is:"+year+"-"+month+"-"+day);
}
else if (isLeapYear(year) && this.month == 2 && this.day == 29) {
this.month = month + 1;
System.out.print("Next day is:"+year+"-"+month+"-1");
}
else if (this.month == 12 && this.day == mon_maxnum[month]) {
this.year = year + 1;
System.out.print("Next day is:"+year+"-1-1");
}
else {
this.month = month + 1;
System.out.print("Next day is:"+getYear()+"-"+month+"-1");
}
}
}
先从主方法中获取年月日的信息,之后再进行各种方法的运用。其中创建了一个每月对应多少天的数组
该数组第一个值赋值为0未了方便后面操作时1月对应mon_maxnum[1]以此类推,以减少出错概率。
在进入最终日期运算之前,首先要判断日期是否合法,其中包括年份是否超规定范围,月份是否在1到12之间,以及每月对应的天数是否超出了上限
对于2月的特殊情况,通过判断是否为闰年来重新为2月天数设置上限
当遇到日期或月份或年份需要加一时,不能直接再print函数中进行变量的加一后输出例如
而应该是year += 1;之后再进行输出。
同时我们还需要考虑当跨越月份时,月份需要加1且日期需要从1开始重新计算,而算得的日期跨过12月31号时,需要进行年份加一月份归1日期归1的操作。
大致需要注意的细节都在于此,在编写该题过程中,也是意识到对各种特殊情况的考虑不够全面,这也就导致浪费了大量的时间,降低了效率。
参考题目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”格式返回日期值
应用程序共测试三个功能:
- 求下n天
- 求前n天
求两个日期相差的天数
输入格式:
有三种输入方式(以输入的第一个数字划分[1,3]):
- 1 year month day n //测试输入日期的下n天
- 2 year month day n //测试输入日期的前n天
- 3 year1 month1 day1 year2 month2 day2 //测试两个日期之间相差的天数
输出格式:
- 当输入有误时,输出格式如下:
Wrong Format
- 当第一个数字为1且输入均有效,输出格式如下:
year1-month1-day1 next n days is:year2-month2-day2
- 当第一个数字为2且输入均有效,输出格式如下:
year1-month1-day1 previous n days is:year2-month2-day2
- 当第一个数字为3且输入均有效,输出格式如下:
The days between year1-month1-day1 and year2-month2-day2 are:值
输入样例1:
在这里给出一组输入。例如:
3 2014 2 14 2020 6 14
输出样例1:
在这里给出相应的输出。例如:
The days between 2014-2-14 and 2020-6-14 are:2312
输入样例2:
在这里给出一组输入。例如:
2 1834 2 17 7821
输出样例2:
在这里给出相应的输出。例如:
1834-2-17 previous 7821 days is:1812-9-19
输入样例3:
在这里给出一组输入。例如:
1 1999 3 28 6543
输出样例3:
在这里给出相应的输出。例如:
1999-3-28 next 6543 days is:2017-2-24
输入样例4:
在这里给出一组输入。例如:
0 2000 5 12 30
输出样例4:
在这里给出相应的输出。例如:
Wrong Format
<代码如下>
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int year = 0;
int month = 0;
int day = 0;
int choice = input.nextInt();
if (choice == 1) { // test getNextNDays method
int m = 0;
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
DateUtil date = new DateUtil(year, month, day);
if (!date.checkInputValidity()) {
System.out.println("Wrong Format");
System.exit(0);
}
m = input.nextInt();
if (m < 0) {
System.out.println("Wrong Format");
System.exit(0);
}
System.out.print(date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " next " + m + " days is:");
System.out.println(date.getNextNDays(m).showDate());
} else if (choice == 2) { // test getPreviousNDays method
int n = 0;
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
DateUtil date = new DateUtil(year, month, day);
if (!date.checkInputValidity()) {
System.out.println("Wrong Format");
System.exit(0);
}
n = input.nextInt();
if (n < 0) {
System.out.println("Wrong Format");
System.exit(0);
}
System.out.print(
date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " previous " + n + " days is:");
System.out.println(date.getPreviousNDays(n).showDate());
} else if (choice == 3) { //test getDaysofDates method
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
int anotherYear = Integer.parseInt(input.next());
int anotherMonth = Integer.parseInt(input.next());
int anotherDay = Integer.parseInt(input.next());
DateUtil fromDate = new DateUtil(year, month, day);
DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay);
if (fromDate.checkInputValidity() && toDate.checkInputValidity()) {
System.out.println("The days between " + fromDate.showDate() +
" and " + toDate.showDate() + " are:"
+ fromDate.getDaysofDates(toDate));
} else {
System.out.println("Wrong Format");
System.exit(0);
}
}
else{
System.out.println("Wrong Format");
System.exit(0);
}
}
}
class DateUtil {
private int year;
private int month;
private int day;
int[] mon_maxnum = {0,31,28,31,30,31,30,31,31,30,31,30,31};
DateUtil(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}
int getYear() {
return year;
}
void setyear(int year) {
this.year = year;
}
int getMonth() {
return month;
}
void setmonth(int month) {
this.month = month;
}
int getDay() {
return day;
}
void setDay(int day) {
this.day = day;
}
public boolean isLeapYear(int year) {
if (year % 400 == 0 || year % 4 == 0 && year % 100 != 0)
return true;
else
return false;
}
public boolean checkInputValidity() {
if(month > 0 && month <=12)
{
if (mon_maxnum[month] >= day && month != 2 && year >= 1820 && year <= 2020 && day >=1)
return true;
else if (isLeapYear(year) && month == 2 && day <= 29 && day > 0)
return true;
else if (!isLeapYear(year) && month == 2 && day <= 28 && day > 0)
return true;
else
return false;
}
else
return false;
}
public DateUtil getNextNDays(int n) {
int year1 = this.year;
int month1 = this.month;
int day1 = this.day;
while(n > 366) {
if (!isLeapYear(year1)) {
n -= 365;
year1++;
}
else {
n -= 366;
year1++;
}
}
while(n > mon_maxnum[month1]) {//算出跨越了几年几月后剩余几天
if (!isLeapYear(year1)) {//非闰年情况
while(n > mon_maxnum[month1]) {
n -= mon_maxnum[month1];
month1++;
if(month1 > 12) {
year1 += 1;
month1 = 1;
break;
}
}
}
else if (isLeapYear(year1)) {//闰年情况
if(month1 != 2) {
while (n > mon_maxnum[month1]) {
if (month1 == 2)
n -= 29;
else
n -= mon_maxnum[month1];
month1++;
if(month1 > 12) {
month1 = 1;
year1 += 1;
break;
}
}
}
else if(month1 == 2 && n > 29) {
month1++;
n -= 29;
}
}
}
if (isLeapYear(year1)) {
if (day1 + n > 29 && month1 == 2)
{
day1 = n - 29;
month1++;
}
}
else if (day1 + n > mon_maxnum[month1]) {
n = n-(mon_maxnum[month1] - day1);
day1 = 0;
month1++;
day1 = n + day1;
}
else
day1 += n;
if (month1 == 13)
month1 = 1;
DateUtil date1 = new DateUtil(year1, month1, day1);
return date1;
}
public DateUtil getPreviousNDays(int n) {
int year1 = this.year;
int month1 = this.month;
int day1 = this.day;
int flag = 0;
while(n != 0) {
if (day1 > n) {
day1 -= n;
flag++;
}
else {
n = n - day1;
month1 -= 1;
if (month1 == 0) {
month1 = 12;
year1 -= 1;
}
if (month1 == 2 && isLeapYear(year1))
day1 = 29;
else
day1 = mon_maxnum[month1];
}
for (int i = month1; n > mon_maxnum[i]; i--) {
if (i == 2 && isLeapYear(year1))
n -= 29;
else
n -= mon_maxnum[i];
month1 -= 1;
if (month1 == 0) {
month1 = 12;
year1 -= 1;
i = 13;
}
if (month1 == 2 && isLeapYear(year1))
day1 = 29;
else
day1 = mon_maxnum[month1];
}
if (day1 > n && flag != 1) {
day1 -= n;
n = 0;
}
if (flag == 1)
n = 0;
}
DateUtil date1 = new DateUtil(year1, month1, day1);
return date1;
}
public boolean compareDates(DateUtil date) {
if (this.year > date.year)
return true;
else if (this.year == date.year && this.month > date.month)
return true;
else if (this.year == date.year && this.month == date.month && this.day > date.day)
return true;
else
return false;
}
public boolean equalTwoDates(DateUtil date) {
if (this.year == date.year && this.month == date.month && this.day == date.day)
return false;
else
return false;
}
public int getDaysofDates(DateUtil date) {
int days,t;
days = 0;
if(!compareDates(date)) {
t = this.year;
this.year = date.year;
date.year = t;
t = this.month;
this.month = date.month;
date.month = t;
t = this.day;
this.day = date.day;
date.day = t;
}
if (compareDates(date)) {
if (this.year > date.year) {
this.year -= 1;
date.year += 1;
if (this.year == date.year && isLeapYear(this.year))
days = 366;
else if (this.year == date.year && !isLeapYear(this.year))
days = 365;
else {
this.year += 1;
date.year -= 1;
days = (this.year - date.year-1) * 365;
}
for (int i = date.month + 1; i <= 12; i++) {
if(isLeapYear(date.year) && i == 2)
days += 29;
else
days += mon_maxnum[i];
}
for (int i = 1; i < this.month; i++) {
if (isLeapYear(this.year) && i == 2)
days += 29;
else
days += mon_maxnum[i];
}
if (date.month == 2 && isLeapYear(date.year))
days = days + 29 - date.day + this.day;
else
days = days + mon_maxnum[date.month] - date.day + this.day;
}
else if (this.year == date.year && this.month > date.month) {
days = this.day;
if (isLeapYear(date.year) && date.month == 2)
days = days + 29 - date.day;
else
days = days + mon_maxnum[date.month] - date.day;
date.month += 1;
for (int i = date.month; i < this.month; i++)
if (isLeapYear(i)) {
if (i == 2)
days += 29;
else
days += mon_maxnum[i];
}
}
else
days = this.day - date.day;
for (int i = date.year + 1; i < this.year; i++) {
if (isLeapYear(i))
days++;
}
}
return days;
}
public String showDate() {
return this.year+"-"+this.month+"-"+this.day;
}
}
在7-3的基础上,需要将
这些方法写入类中,此时需要注意取得下n天和前n天的方法返回值为DateUtil类型
最终编写完成后的类图为
在实现计算最终日期的算法时,我们的大致顺序应该为
判断日期是否合法
判断是否是闰年
判断当下日期是否为2月或12月
之后计算最终日期
而在计算两日期之前相差天数的算法上,我先采用将年份大的日期赋给this.的参数,小的赋给date.的参数一边后续的计算
大致算法为,先将两日期相差多少年乘以365以算出天数,再将不满一年相差的月数对应天数算出,最后将两日期的剩余天数算出。
但由于不是每年都是365天,所以我们需要对两日期间的年份进行遍历以计算之间有几个闰年,最后在计算总天数是加上少算的这几天。
遍历如下
(3)采坑心得:尽量在eclipse上编写代码,利用编译环境的优点,将所有语法错误纠正,并记录下来,以提高效率。而在调试过程中发现测试点不通过时,及时使用debug去进行测试,来达到快速查找逻辑错误出现在何处,而在不知道测试点问题出在哪里时,应该往题目情景中比较特殊的点出发,逐步排查问题,来达到思路清晰的去解决问题,而不是盲目的一个一个点去测试,因为这些你随便测试的点大部分所利用到的算法都是一致的,所以在进行这些重复测试只会让费掉自己的耐心和时间。此下便是无用测试后提交多次却没能解决问题的结果,而且几次提交的时间间隔非常短暂,这也是当时在多次提交后无果失去耐心急于得分的表现。
(4)改进建议: 在面对题目时不要立马选择开始敲,而应该是去思考解决的办法,以及整体思路和需要运用到那些东西,在必要情况下可以拿出笔和纸将思路写下,这样不仅可以提高效率,同时还能在编写代码前提前知道那些需要运用到的东西是自己不知道如何运用的,然后去书上找到相应的知识点去系统的学习。我始终觉得网上的某些知识写的太泛,不够严谨,也没有书上写的明确,所以能从书上解决的问题尽量通过书上去解决,这样在将来碰到一些基础的问题时,不至于在底层理解上出现重大问题。在碰到自己实在无法解决的问题是,可以通过同学寻求思路上的帮助,这也是锻炼了自己的交流能力,能够去更好的更新自己的思路。
(5)总结:在完整进行了三次实验之后,无论是对java的基础语法的学习,还是对其面向对象的特殊性都有了初步的理解与认识,在完成实验的过程中,遇到了很多问题,这都需要我去通过无论是看书还是上网去寻求答案。而相较于上学期所学的c语言来说,每道题的测试点要求真高了,出现了以前未曾出现过的超时错误,同时部分题目还出现了未给出输出类型要求,但是测试点想要通过却必须强制转化成某种特定的类型才能通过,等等新出现的问题都需要我去静下心来解决,只有在不断地面对困难并克服困难的情况下,个人的编程能力与对代码的理解能力才能得到锻炼与提升,因此在接下来的学习过程中,要提高学习效率,尽力去学习。
而对于课程教学安排,个人认为任务是相对来说较于繁重,这也就导致很多同学都觉得和高中无异,当然,毕竟作为一类工科专业,适当的实操训练是有必要的,但是近期的作业量不知道是个人的原因还是其他,已经是整个周末三分之二的时间都要用来写作业才能写完的程度了,这也让我觉得这个大学的周末甚至没有周一到周五过的轻松。也是希望能适量减轻作业压力,每个人编程能力一定是有差异的,而过多的作业堆积也会让部分学生产生负面情绪而想方设法地去寻找捷径,进而恶性循环。如果编程能力不够好,在花了大量时间却没能把作业完成,就算个人总结的反思再好,在如此迭代的作业压力下,总会对自己产生怀疑进而对这个专业失去信心,所以我觉得学校应该适当减轻学生学业压力,当然那些摆烂的人无论怎么给他们减压都会觉得不满足,在此意见仅仅是对于那些想努力学好的学生尤其是那些在想摆烂又想学之间徘徊的人群。还有就是java课程的教室,有很大的问题,教室窄又长,如果想要抢到前排的位置,在前一节课下课后不快马加鞭跑,很难有机会抢到,这也就导致想学但是没抢到位置的人坐后面没法学,而且这个教室的黑板又小,希沃白板也小,坐前面有时都看不清楚上面写的是什么东西。而对于老师所教课程,觉得大致是能听懂,但感觉从来没用到过,这也就让我对上课所学的东西感到迷茫,抽象。