maojj

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

 

题目集1~3的总结性Blog

前言

      在完成前面三次pta的大作业后,对其进行一定的总结与分析。

      1.总体来看,前面三次的大作业中,第三次作业的难度是最高的。

      2.第一次作业主要是一些简单基础的题目,能够很快就得出一个思路,基本上就是一些对if,for语句的考察。

      3.第二次作业的第二题有一定的难度,导致我一开始没有一个很清晰的思路,写代码都是写一步看一步,最后写出来的代码结构比较混乱,圈复杂度也比较高。

      4.第三次作业整体的难度就很高,但是循序渐进,后面两题是从第一题的基础上衍生出去的,一开始写第一题的时发现有好多测试点不知道是什么,经过反反复复的尝试,才拿到满分,但后面两题虽然是第一题的拓展,却需要设计算法,进行相应的计算,而且较第一题,多了几个判断格式错误的测试点,导致我第二题判断格式错误的代码改了又改,最后的代码估计只有自己能看懂,归根结底还是自己的功底不够厚,无法有一个较为清晰的思路,希望在以后的学习中能够提升自己这一方面的能力。

第一次作业——题目集01 7-7

      题目集01 7-7的题目是判断三角形类型,是考察对整数,浮点型数据的处理和选择语句的综合使用。

  整体思路介绍

      1.题目集01 7-7其实并不难,在看完题目之后基本有了一个较为清晰的思路。

      2.首先应通过输入三条边的边长来判断是否能构成三角形,再通过进一步判断三角形的类型。

      3.题目需要我们判断控制输入边长的范围,为[1,200],否则则输出"Wrong Format"。

      4.题目需要用多个if语句判断是否为直角三角形,等腰三角形,等边三角形,等腰直角三角形,一般三角形。

      5.double类型的数据在计算平方和时会丢失精度导致判断直角三角形时会出错,所以应该通过两边的平方和减去另一边的平方和的值小于0.01来判断。

      

 

 

  度量分析

      使用SourceMonitor软件生成

      

 

  核心代码分析

if(x<1||x>200||y<1||y>200||z<1||z>200)   //判断输入的边长是否在[1,200]这个范围内
        {
            System.out.print("Wrong Format");
        }
        else
        {
            if(x>=y+z||y>=x+z||z>=x+y)    //若任意两边之和不大于第三边则无法构成三角形
            {
                System.out.print("Not a triangle");
            }
            else
            {
                if(x==y&&y==z)       //若三条边相等则为等边三角形
                {
                    System.out.print("Equilateral triangle");
                }
                else
                {
                    if(x==y||x==z||y==z)      //判断是否为等腰三角形
                    {
                        if(x==y&&(x*x+y*y-z*z)<0.01||x==z&&(x*x+z*z-y*y)<0.01||y==z&&(y*y+z*z-x*x)<0.01)   //(double类型的数据计算平方和是会丢失精度,如计算无理数的平方和)
                        {
                            System.out.print("Isosceles right-angled triangle");
                        }
                        else
                        {
                            System.out.print("Isosceles triangle");     //否则则为等腰三角形
                        }
                    }
                    else if(x*x+y*y==z*z||x*x+z*z==y*y||y*y+z*z==x*x)   //判断是否为直角三角形
                    {
                        System.out.print("Right-angled triangle");
                    }
                    else                             
                    {
                        System.out.print("General triangle");           //除上述情况外的为一般三角形
                    }
                }
            }
        }

  采坑心得

      

 

 

       一般来说,我们对直角三角形的判断都会用上勾股定理,但是对于double类型的数据,在计算平方和时会丢失精度,特别是对于无理数来说,所以一开始我就没有拿到等腰直角三角形测试点的分,后来使用了一定精度判断才通过了等腰直角三角形的测试点。

    优点

      1.条理清晰,简洁明了。

      2.在判断等腰直角三角形时与判断直角三角形分开判断。

      3.考虑到了double类型的数据计算平方和时会丢失精度(比如计算无理数时),使用了(x*x+y*y-z*z)<0.01避免这种情况。

    缺点

      1.有些地方的判断条件显的多余,可以进行一定的简化。

      2.一开始并没有想到double类型的数据计算平方和时会丢失精度,导致判断等腰直角三角形的测试点过不去,后面才使用了(x*x+y*y-z*z)<0.01解决了这种情况。第二次作业 第二次作业集02 7-2

  改进建议

      根据代码的度量分析图发现,圈复杂度比较高,应该是if进行判断的时候的结构出现了一定的问题,虽然最后测试点通过了,但总体来说这串代码比较失败,可以改良一下if的条件,就能很大程度上减少代码的复杂程度。

 第二次作业——题目集02 7-2

      题目集02 7-2是串口字符分析,考察对字符串的处理与选择语句的综合使用。

  整体思路分析

      1.题目要求对输入一串由0和1组成的字符串进行分析和拆解。

      2.可先定义一个字符串接收输入进来的数据,再用toCharArray()方法将其分解成字符数组。

      3.有效数据的起始位为0,因此可以使用循环检测第一次出现0的地方。

      4.在第一次出现0后,对后八位数字进行记录。

      5.对第九位和第十位数字进行相应的判断,判断结束后将循环向后加十一个数开始下一组数据的检测。

      

 

 

  度量分析

      

 

  核心代码分析

     下面分析一下本题的核心代码。 

if(flag==0||a.length<11)   //判断数据是否有11个,flag是前面判断是否有0的标记 
        {
            System.out.print("null data");
        }
        else
        {
            String str;
            str=s;
            for(int i=0;i<a.length;i++)
            {
                if(a[i]=='0')      //若有元素为0,则开始进行判断
                {
                    count++;     //count为序号
                    if(i+9<a.length)    //这里需要判断i+9<a.length是因为下面用到了substring方法,防止越界
                    {
                        str=s.substring(i+1,i+9);
                        x=0;
                        for(int k=i+1;k<i+10;k++)
                        {
                            if(a[k]=='1')      //记录数据有几个1
                            {
                                x++;
                            }
                        }
                    }
                    if(s.charAt(i+10)!='1')      //如果最后一个数字不是结束为1
                    {
                        if(count==1)      //如果序号为1
                        {
                            System.out.print(count+":"+"validate error");
                            i+=10;
                        }
                        else
                        {
                            System.out.println();
                            System.out.print(count+":"+"validate error");
                            i+=10;
                        }
                    }
                    else if(x%2==0&&s.charAt(i+10)=='1')  //奇偶性判断
                    {
                        if(count==1)
                        {
                            System.out.print(count+":"+"parity check error");
                            i+=10;
                        }
                        else
                        {
                            System.out.println();
                            System.out.print(count+":"+"parity check error");
                            i+=10;
                        }
                    }
                    else
                    {
                        if(count==1)
                        {
                            System.out.print(count+":"+str);
                            i+=10;
                        }
                        else
                        {
                            System.out.println();
                            System.out.print(count+":"+str);
                            i+=10;
                        }
                    }
                }
            }
        }

  采坑分析

      

 

 

       在使用方法时,一定考虑到是否会越界,本题我一开始并没有写这个i+9<a.length,但后面发现有些测试数据在substring这个方法越界了,后来发现如果i+9大于了s的长度就越界了。另外这道题目中的奇偶性判断并不是指对倒数第二个数进行奇偶判断,而是对加上倒数第二个数的九个数字有几个1进行奇偶判断,若有奇数个1则通过,否则则输出parity check error。

    优点

      1.代码整体上条理清晰,如果有地方错了比较容易进行修改。

      2.在对字符串的处理时,将字符串转化为字符数组进行处理会容易很多。

    缺点

      1.代码的圈复杂度位21,写的较为复杂,bug也比较多。

      2.在写的时候没有一个特别清晰的思路,基本上是想到什么写什么。

      3.在进行输出时,可以不用count==1来判断是否为第一行,这里多此一举了。

  改进建议

      在进行输出时,可以不用count==1来判断是否为第一行,直接使用System.out.println(count+":"+"parity check error")即可,当时觉得如果只输出一行不需要换行,但是后来发现并无大碍。

第三次作业——题目集03 7-1

      本次题目集考察对字符串数组的处理。

  思路分析介绍

      1.题目要求我们对输入的一串字符串进行相应的拆解与判断。

      2.可以将输入的字符串以空格进行分割,再利用循环根据空格分割出字符串的长度进行以逗号对字符串进行分割。

      3.将以逗号进行分割后的字符串分别进行数据的格式判断。

      4.对输入字符串空格数目进行判断。

      5.对以逗号分割的字符进行double类型的转化,并计算出两点间的距离。

      

 

 

  度量分析

      

 

  核心代码分析

for(int i=0;i<c.length;i++)
        {
            if(c[i]==',')    //逗号个数的判断
            {
                count1++;
            }
        }
        if(count1>2)
        {
            flag=1;
        }
        String a[]=s.split("\\s");
        if(a.length>2)    //空格个数的判断
        {
            flag1=1;
        }
        if(count1<=2)
        {
        for(int i=0;i<a.length;i++)
        {
            String[] b=a[i].split(",");
            if(b.length>2)
            {
                flag=1;
            }
            for(int j=0;j<b.length;j++)
            {
                count=0;
                for(int k=0;k<b[j].length();k++)
                {
                    if(b[j].charAt(k)=='.')    //小数点个数的判断
                    {
                        count++;
                        if(k+1==b[j].length())   //如果小数点后面没有数据了就为非法
                            flag=1;
                    }
                }
                if(count>=2)
                {
                    flag=1;
                }
                if(b[j].charAt(0)=='+'||b[j].charAt(0)=='-')    //如果第一个为符号
                {
                    if(b[j].charAt(1)<'0'||b[j].charAt(1)>'9')   //第二个数不为数字 
                    {
                        flag=1;
                    }
                    if(b[j].charAt(1)=='0'&&b[j].charAt(2)!='.')   //第二个为0但是第三个不为小数点
                        flag=1;
                }
                if(b[j].charAt(0)=='0'&&b[j].charAt(1)!='.')     //第一个为0但是第二个不为小数点
                    flag=1;
            }
        }
        }

  改进建议

      代码在复杂程度上比较高,但这题我只能说想不到如何去进去更好的优化了,已经使用了循环对冗杂的代码进行简化,并在if判断时条件写的很有条理,但是可能这题本身就是如此,又或是我自己能力不够,我无法对其进行很好的改进。

第三次作业——题目集03 7-2

      这题是对上题的衍生。

  思路分析介绍

      1.本题可以说是上题的升级版,但更复杂,也多了些需要判断的非法格式。

      2.基本思路和上题一样,但因为这题之前都没有面对对象来设计,所以这题使用面向对象的方法。

      

 

 

  度量分析

      圈复杂度45,写这题时代码基本上都是慢慢改出来的。

      

 

 

   核心代码分析

      判断输入的字符串是否合法的方法:

public static int islegal(String s)
    {
        int count;
        int count1=0;
        int count2=0;
        int count3=0;
        int flag=0;
        int flag1=0;
        int dotnum=0;         //dotnum为点的个数
        String[] a=s.split(":");
        if(s.charAt(0)=='1')
        {
            dotnum=2;
        }
        else if(s.charAt(0)=='2'||s.charAt(0)=='3')
        {
            dotnum=3;
        }
        else if(s.charAt(0)=='4'||s.charAt(0)=='5')
        {
            dotnum=4;
        }
        if(s.charAt(0)>='0'&&s.charAt(0)<='5'&&s.charAt(1)!=':')
        {
            flag=1;
            dotnum=5;
        }
        char[] n=s.toCharArray();
        for(int i=0;i<n.length;i++)
        {
            if(n[i]==':')     //若有多个冒号
                count2++;
        }
        if(count2>=2)
        {
            flag=1;
        }
        char[] c=a[1].toCharArray();
        for(int i=0;i<c.length;i++)
        {
            if(c[i]==','&&c[i+1]==',')   //连续两个逗号
            {
                count1++;
            }
            if(c[i]==' '&&c[i+1]==' ')   //连续两个空格
            {
                count3++;
            }
        }
        String[] p=a[1].split("\\s");
        if(p.length!=dotnum)
        {
            flag1=1;
        }
        if(count1>=1)
        {
            flag=1;
        }
        if(count3>=1)
        {
            flag=1;
        }
        else {
            String b[] = a[1].split("\\s");
            if (count2 < 2) {
                for (int i = 0; i < b.length; i++) {
                    String[] m = b[i].split(",");
                    if (m.length > dotnum) {
                        flag = 1;
                    }
                    for (int j = 0; j < m.length; j++) {
                        count = 0;
                        for (int k = 0; k < m[j].length(); k++) {
                            if (m[j].charAt(k) == '.') {                 //判断逗号个数
                                count++;
                                if (k + 1 == m[j].length())
                                    flag = 1;
                            }
                        }
                        if (count >= dotnum) {
                            flag = 1;
                        }
                        if (m[j].charAt(0) == '+' || m[j].charAt(0) == '-') {
                            if (m[j].charAt(1) < '0' || m[j].charAt(1) > '9') {         //若第二个数不为0到9中的一个
                                flag = 1;
                            }
                            if (m[j].charAt(1) == '0' && m[j].length() > 2)          //若为+0或-0
                                if (m[j].charAt(1) == '0' && m[j].charAt(2) != '.')   //若0后不是小数点
                                    flag = 1;
                        }
                        if (m[j].charAt(0) == '0' && m[j].length() > 1) {
                            if (m[j].charAt(0) == '0' && m[j].charAt(1) != '.')
                                flag = 1;
                        }
                    }
                }
            }
        }
        if(flag==1)
        {
            System.out.println("Wrong Format");
        }
        else if(flag1==1&&flag==0)
        {
            System.out.println("wrong number of points");
        }
        else
            return 1;
        return 0;
    }

  采坑分析

      

 

       在选项五进行交点计算时,我一开始是用了斜率进行计算,分别将两条直接的斜率求出来,然后求出交点,但是我发现pta上总有一个测试点过不去,调试的话也调试不出来什么东西,最后不得已采用了理由向量进行相应的计算,一提交居然通过了测试点,所以到现在也不知道那个测试点是什么。

      

 

       一开始我以为是因为这里输出了-0.0所以过不去测试点,后来将这个改过来了也没有过那个测试点。我感觉这题最关键的就是对输入字符串格式是否合法的判断。

  改进建议

      1.这题写字符串格式是否合法的那个方法时,总会有测试点过不去,较第一题而言,这一题多了对前面选项已经冒号的判断,但我还发现还多了对连续两个空格或者逗号的测试点。

      2.这题的圈复杂度高达45,写的时候基本就是想到什么非法格式,就强行写一个语句给他加进去,并没有考虑到如何对代码进行优化,导致代码总体的复杂度很高,而且本题虽然是面向对象,但依旧采用的是赋值的手段,没有使用构造方法,这应该也是增大复杂度的一个点。最后在算交代时,以后尽量使用向量进行计算,使用斜率进行计算虽然pta上的测试数据出来是没有问题,但测试点并过不去,当时苦恼了很久,才了解到向量法可以通过。

第三次作业——题目集03 7-3

      本题是对第一题的衍生,最终有两个测试点没有过。

  思路分析介绍

      1.本题思路和前面的一样。

      2.本题涉及到了射线法,需要去找到相关资料并进行学习。

      

 

 

  度量分析

      圈复杂度达到了121,没有去写很多的方法。

      

 

 

   采坑分析

      1.选项四代码分析

      

 

       我自己审视了一下,之所以会达到这么高的圈复杂度,就是因为我把这些算法都写在了一起,应该多写几个方法进行计算,不然这样写出来的代码就算过了测试点也是漏洞百出。对于选项四这里,进行直线与三角形的交点的计算继续采用向量的方法,但后面对于面积的计算,因为无法得知两个交点到底是与哪个顶点构成三角形,所以我使用了一些num1,num2,num3这样的标记变量进行标记,这样就能得知是哪交点是在那条边上的。方便后面进行面积的计算。而对于三角形面积的计算,如何使用三点坐标算面积,也是网上搜索之后的结果。

      2.判断小数并保留

      

 

       这里需要判断小数点后有几位数字,如果是小于六位就原样输出,大于六位则需要四舍五入保留六位小数再输出,这里是先检测小数点个数,然后使用字符串进行相应的转化,最后输出的方法。

  改进建议

      这一题为什么会有这么高的复杂度,我感觉是因为我没有将功能方法化,每个功能我都是写在了一个方法里面,导致在这个方法中复杂度过高。并且在判断选项时,没有使用switch语句进行判断,而是使用使用了if语句,这里就有极大的增加的复杂度。然后另一方面也是因为这题的算法的确十分的复杂,在设计的时候就十分的困难,比如在考虑直线与三角形的交点有几个时,就会有很多钟方法,而我也是和我同学一起讨论出来的一种,最后确实通过了很多的测试点,但遗憾还是我没有把他们写成方法。



总结

   前面两次的大作业可能我觉得用不上面向对象就没有面向对象,但是后面写第三次大作业时,我发现面向对象还有很多我不懂的地方,无法运用的很好,以后写这些作业都要保证是按面向对象来写,不然学面向对象程序设计也就失去了意义。根据这三次作业,我发现了自己的一个很大的不足,就是只管写,不会去考虑整体的结构与复杂度,导致我这几道题目的代码复杂度都比一般人高,这样哪怕是过了我最后是满分,我也觉得比不上那些复杂度低的人。希望在以后的学习中,我能够在写之前就有一个较为清晰的思路,设计出相应的结构,并在写完之后进行优化。

   总体来说,这一个月我学到了很多,老师在课堂上讲的需要我课后去加深巩固,去找到相应的资料进行学习,才能越走越远,而不是出现121的最高复杂度。   

 

 

------------恢复内容结束------------

posted on 2022-04-09 23:03  Moray丶  阅读(79)  评论(0)    收藏  举报