• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

Qi-09

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

作业总结1

  第一次作业题目量较大,知识点较广(1,2,4,12题选择结构。3,7,9题循环结构。5,6,8,10题对字符串的操作。)但题目难度不是特别高。

  第二次作业题目量较少,偏向于对测试点的考虑(测试点较多),题目相对简单。

  第三次作业题目量少,要求对程序的运行更高效。

 

 

 

 

 

 

 

 

 

 设计与分析

  第三次作业7-3时要考虑各种特殊日期:每月最后一天(第二天月份+1,日期归1),每年最后一天(年份+1,月份归 1,日期归1),2.28(如果是平年,按每月最后一天算,如果是闰年日期+1),2.29(平年非法输入,闰年按每月最后一天算)。

  

 1     public void getNextDate() {
 2         if(checkInputValidity()) {//checkInputValidity()判断日期是否合法
 3             if(month==2&&isLeapYear(year)&&day==29) {
 4                 System.out.println("Next day is:"+year+"-3-1");
 5                 return;
 6             }
 7             else if( month==12&&day==31) {
 8                 System.out.println("Next day is:"+(year+1)+"-1-1");
 9                 return;
10             }
11             else if(day==mon_maxnum[month]&&(month!=12)) {//mon_maxnum是int型数组记录平年的月末天数{0,31,28,31,...,30,31}
12                 if(isLeapYear(year)&&month==2) { //isLeapYear判断是否为闰年
13                     System.out.println("Next day is:"+year+"-"+month+"-"+(day+1));
14                 }
15                 else {
16                     System.out.println("Next day is:"+year+"-"+(month+1)+"-1");
17                 }
18                 return; 
19             }
20             else {
21                 System.out.println("Next day is:"+year+"-"+month+"-"+(day+1));
22             }
23         }
24         else {
25             System.out.println("Date Format is Wrong");
26         }
27     }
28 }

 

 

 第三次作业7-4是7-3的plus版本,难度较大。

 

 

 分析:对于求下n天可以先让日期+n,当n与日较小(如3.1的下3天是3.4)可以直接得到答案。但是当n和日较大时,比如3.28的下5天 ,得到的是3.33。我们都知道3月是没有33天的。如果让小朋友算,他们会扳手指头29,30,31,1,2这样数5天。所以很自然的想到,当+n后日期非法了应该减去这个月的日期数,月+1(3.28+5=3.33 => (3+1)月(33-31)日 => 4.2)。

 1 public DateUtil getNextNDays(int n){
 2     DateUtil nextDay=new DateUtil(this.year,this.month,this.day);
 3     nextDay.day+=n;
 4     
 5     while(!nextDay.checkInputValidity()) {    // nextday+n后如果非法就进入循环
 6         
 7                 if(nextDay.month==2 && nextDay.isLeapYear(nextDay.year)) {
 8                     nextDay.month++;
 9                     nextDay.day=nextDay.day-29;
10                 }// 润2月
11 
12                 else if( nextDay.month==12) {
13                     nextDay.year++;
14                     nextDay.month=1;
15                     nextDay.day=nextDay.day-31;
16                 }// 12月
17                 
18                 else {// mon_maxnum是int类型数组记录月末天数{0,31,28,31,30,...,30,31}
19                     nextDay.day=nextDay.day - mon_maxnum[nextDay.month];
20                     nextDay.month++;
21                 }// 其他月份
22             }    // 日期合法后跳出循环
23     
24     return nextDay;
25 }

于是我们得到了上面这串代码,但是当n很大时比如 300w 那么这个代码一次减小30,大约要近10w次才能跳出循环效率低下。所以我们想到 4年一润和400年一润 可以把周期定为400年(每100年会存在平年所以不用4年做一个周期)。400年里有100-3=97个闰年也就是 365*400+97=146097天。

if(nextDay.day > 150000) {
            int o=0,u=0;
            o=nextDay.day/146097;
            u=nextDay.day%146097;
            nextDay.day=u;
            nextDay.year=nextDay.year+400*o;
//                nextDay.year=nextDay.year+400;
//                nextDay.day=nextDay.day-146097;
        } //n很大
        else {...}

146097似乎也是一个很大的数,如果我的n就等于146096那程序也要运行很久所以我们可以计算14w天里大概有多少年和多少闰年。所以上面else{...}里可以加入计算年的方法

 1 if(nextDay.day>800) {
 2                 nextDay.day=nextDay.day-400;
 3                 DateUtil date1=new DateUtil(); // 记录初始年份
 4                 DateUtil date2=new DateUtil(); // 记录n-400天后年份
 5                 int o=0,u=0,leapMonth=0;
 6                 o=nextDay.day/365;
 7                 u=nextDay.day%365;
 8 
 9                 date1.day=nextDay.day;
10                 date1.month=nextDay.month;
11                 date1.year=nextDay.year;
12                 
13                 nextDay.year=nextDay.year+o;
14                 
15                 date2.day=nextDay.day;
16                 date2.month=nextDay.month;
17                 date2.year=nextDay.year;
18                 
19                 for(int i=date1.year;i<=date2.year;i++) {
20                     if(isLeapYear(i)) {
21                         leapMonth++;
22                     }            
23                 } // 记录n-400天后有多少闰年
24                 //减去开始和结尾可能不会经历的润2月
25                 if(date1.month>=3&&isLeapYear(date1.year)) {
26                     leapMonth--;
27                 }
28                 if(date2.month<3&&isLeapYear(date2.year)) {
29                     leapMonth--;
30                 }
31                 
32                 nextDay.day=u-leapMonth+400; // 开始n减去了400,现在补加回来
33             }

这样我们要计算的天数最多就是800天了.

踩坑心得

上面的代码可能会有些疑惑:为什么要减去400天?

 

 

 当输入上述测试用例(1999.3.28的后6543天)后 黄色部分day 变为负数了,但我们并没有做对于负数的处理(这个在前n天会使用到),这样进入while()循环后就会变成死循环.而400年里有397个闰年所以leapMonth最大为397减去部分大于397就可以.至于day大于800是为了让day减去400后能保证有一年.

求上n天就异曲同工了 

 1     public DateUtil getPreviousNDays(int n) {
 2         DateUtil previousDay=new DateUtil(this.year,this.month,this.day);
 3         previousDay.day -= n;
 4         while(previousDay.day<=0) {
 5             if(Math.abs(previousDay.day) > 150000) {
 6                 previousDay.year=previousDay.year-400;
 7                 previousDay.day=previousDay.day+146097;
 8             }
 9             else {
10                 if(previousDay.month==3&&previousDay.isLeapYear(previousDay.year)) {
11                     previousDay.month--;
12                     previousDay.day=previousDay.day+29;        
13                 }
14                 else if( previousDay.month==1) {
15                     previousDay.year--;
16                     previousDay.month=12;
17                     previousDay.day=previousDay.day+31;
18                 }
19                 else {
20                     previousDay.month--;
21                     previousDay.day = previousDay.day+mon_maxnum[previousDay.month];        
22                 }
23             }
24         }    
25         return previousDay;
26     }//取得year-month-day的前n天日期

至于求两天之间的差的天数,在这之前我们要先比较这两天的先后顺序,首先我们想到的是先比较年再比较月再比较日,但我们可以使用数学里加权重的思想让年的权重>> 月的权重>>日的权重.

1     public boolean compareDates(DateUtil date) {
2         if( (this.year*400+this.month*31+this.day) <= (date.year*400+date.month*31+date.day) ){
3             return true;
4         }
5         else {
6             return false;
7         }
8     }//比较当前日期与date的大小(先后)true this先;

接着我们去考虑两天差的天数

 1     public int getDaysofDates(DateUtil date) {
 2         if(this.equalTwoDates(date)) {
 3             return 0;
 4         }
 5         DateUtil date1=new DateUtil();    //记录前面的时间
 6         DateUtil date2=new DateUtil();    //记录后面的时间
 7         if(this.compareDates(date)){
 8             date1.day=this.day;
 9             date1.month=this.month;
10             date1.year=this.year;
11             
12             date2.day=date.day;
13             date2.month=date.month;
14             date2.year=date.year;
15         }
16         else {
17             date2.day=this.day;
18             date2.month=this.month;
19             date2.year=this.year;
20             
21             date1.day=date.day;
22             date1.month=date.month;
23             date1.year=date.year;
24         } 
25         
26         int leapMonth=0,n=0;
27         int[] monthDay=new int[] {0,0,31,59,90,120,151,181,212,243,273,304,334}; // monthDay是记录平年月份所拥有的天数
28         n=(date2.year-date1.year)*365 + (monthDay[date2.month]-monthDay[date1.month]) + (date2.day-date1.day);
29         for(int i=date1.year;i<=date2.year;i++) {
30             if(isLeapYear(i)) {
31                 leapMonth++;
32             }            
33         }
34         if(date1.month>=3&&isLeapYear(date1.year)) {
35             leapMonth--;
36         }
37         if(date2.month<3&&isLeapYear(date2.year)) {
38             leapMonth--;
39         }
40         n=n+leapMonth;
41         return n;
42     }//求当前日期与date之间相差的天数

这部分代码大部分内容都在求n天后解释过了,就不多赘述.27行的monthDay(比如我们计算3.26号是这年的第几天会这样算:26+前两个月)记录的就是每月的前n-1个月有多少天.

 

总结:

  学到了什么: 这三次练习,让我了解了Java的基础知识(选择结果,循环结构,字符串,数组),还有Java的class(这个类似与c语言的struct但又比struct更加方便,功能性也更强).

  不足:     对于算法效率不够高,有些题目因为运行次数太多超时.

  意见:    希望老师每次作业截止后把答案或者优秀的算法分享出来.

posted on 2023-03-26 16:17  Qi_09  阅读(33)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3