BLOG_3
作者:互联网
(1)前言:本次BLOG主要对过去几周的内容做一个总结,主要是分三次作业做了一个电信计费项目。
1.第一次:经过前面图形判断的非常不人性化折磨,对于本次的错误格式判断有了更深的理解,
2.第二次:第二次题目在题量与数据界定上都友好了许多,没有那么多另人懵逼的测试点,难度相比第一次有了提高,但体验却比第一次良好许多。第二次作业主要的知识点就是String类型了,相比于C繁琐的字符串,Java不管是声明、定义还是使用都方便许多,在使用时有着非常良好的体验感,其中String类的诸多有用的方法也给我们带来了很多便利以及减少了程序的复杂度,其中matches方法直接少了一个for的遍历,确实大开眼界。
3.第三次:第三次作业是最简单的一次,主要是对代码结构的审查和优化,对于题目本身的答案要求只需要简单的添加信息。
(2)设计与分析:
1.第一次电信计费题目;
先上类图:
首先是之前非常折磨人的错误判断,之前是步步拆开字符串分析,而在这次电信计费中用了正则表达式,非常方便快捷。
pattern1=Pattern.compile("u-((079\\d|0701)\\d{7,8})\\s([012])"); pattern2=Pattern.compile("t-((079\\d|0701)\\d{7,8})\\s(\\d{11,12})" + "\\s(\\d{4}\\.(0?\\d|1[0123])\\.(0?[1-9]|1\\d|2\\d|3[0-1])\\s([01]\\d|2[0-4]):([0-5]\\d):([0-5]\\d))" + "\\s(\\d{4}\\.(0?\\d|1[0123])\\.(0?[1-9]|1\\d|2\\d|3[0-1])\\s([01]\\d|2[0-4]):([0-5]\\d):([0-5]\\d))");
2.第三次作业7-1:直接上图说明。
if(s.length()<5){ System.out.println("Wrong Format"); return; } if(s.charAt(0)<'0'||s.charAt(0)>'9'){ System.out.println("Wrong Format"); return; } if(s.charAt(1)!=':'){ System.out.println("Wrong Format"); return; } if((s.charAt(2)<'0'||s.charAt(2)>'9')&&(s.charAt(3)<'0'||s.charAt(3)>'9')){ System.out.println("Wrong Format"); return; } for(int i=0;i<count1;i++){ if((s.charAt(c1[i]-1)<'0'||s.charAt(c1[i]-1)>'9')&&(s.charAt(c1[i]+1)<'0'||s.charAt(c1[i]+1)>'9')){ p=0; break; } if(i==count1-1){ if((s.substring(c1[i]+1).length()>1)&&(s.charAt(c1[i]+1)<'0'||s.charAt(c1[i]+1)>'9')&&(s.charAt(c1[i]+2)<'0'||s.charAt(c1[i]+2)>'9')){ p=0; break; } } else if(i<count1-1) if((s.charAt(c1[i]+1)<'0'||s.charAt(c1[i]+1)>'9')&&(s.charAt(c1[i]+2)<'0'||s.charAt(c1[i]+2)>'9')){ p=0; break; } } if(p==0){ System.out.println("Wrong Format"); return; } for(int i=0;i<count2;i++){ if((s.charAt(c2[i]-1)<'0'||s.charAt(c2[i]-1)>'9')&&(s.charAt(c2[i]+1)<'0'||s.charAt(c2[i]+1)>'9')){ q=0; break; } if((s.charAt(c2[i]+1)<'0'||s.charAt(c2[i]+1)>'9')&&(s.charAt(c2[i]+2)<'0'||s.charAt(c2[i]+2)>'9')){ q=0; break; } } if(q==0){ System.out.println("Wrong Format"); return; } if((Integer.parseInt(s.substring(0,1))+4)/2!=count1){ System.out.println("wrong number of points"); return; } if((Integer.parseInt(s.substring(0,1))+4)/2!=count2+1){ System.out.println("Wrong Format"); return; }
我的思路不是说一点点遍历看格式是否错误,而是直接得到逗号与空格的数量以及逗号和空格的位置(因为逗号数等于数据组数),通过逗号或者空格两侧元素的ASIC码值来初步判定判定是否正确以及数据数目是否符合要求。如果空格的两边都不是数字或者逗号的两边都不是数字那就格式错误;如果一个非数字符号之后紧跟一个非数字元素那就格式错误,如果String长度连最低要求都达不到,也是格式错误……但这些判定中有一部分其实有点蠢(不精确),比如5,5 +,5就判断不出来而5,5 +5,5就可以,诸如此类错误都不能判定,估计测试数也没有很精确,算是比较幸运。
tool=s; for(int i=0;tool.contains(",");i++){ if(i==0) c1[i]=tool.indexOf(","); else if(i>0) c1[i]=tool.indexOf(",")+s.length()-tool.length(); tool=tool.substring(tool.indexOf(",")+1); } tool=s; for(int i=0;tool.contains(" ");i++){ if(i==0) c2[i]=tool.indexOf(" "); else if(i>0) c2[i]=tool.indexOf(" ")+s.length()-tool.length(); tool=tool.substring(tool.indexOf(" ")+1); }
上面是记录空格、逗号位置的方法,先引入工具String类tool,避免改变原有输入s,然后不断找到字符串中第一个空格或逗号,再选取所找到字符后一位到结尾的一段新字符串赋值给tool,如此循环就能记录位置。
int count1=s.length()-s.replace(",","").length(); int count2=s.length()-s.replace(" ","").length
这段代码是计算空格和逗号数量的,用s的长度减去把s中所求字符串换成空字符的字符串长度,去除以所求字符串长度即可得到所求字符串的数量,本题所求字符串也就是一个字符,长度为一。
X=s.substring(0,c1[0]); Y=s.substring(c1[0]+1,c2[0]); x[0]=Double.parseDouble(X); y[0]=Double.parseDouble(Y); if((X.length()>2&&X.charAt(1)=='0')||(X.length()==2&&X.charAt(0)=='0')){ System.out.println("Wrong Format"); return; } if((Y.length()>2&&Y.charAt(1)=='0')||(Y.length()==2&&Y.charAt(0)=='0')){ System.out.println("Wrong Format"); return; } for(int i=1;i<count2;i++){ X=s.substring(c2[i-1]+1,c1[i]); Y=s.substring(c1[i]+1,c2[i]); x[i]=Double.parseDouble(X); y[i]=Double.parseDouble(Y); if((X.length()>2&&X.charAt(1)=='0')||(X.length()==2&&X.charAt(0)=='0')){ System.out.println("Wrong Format"); return; } if((Y.length()>2&&Y.charAt(1)=='0')||(Y.length()==2&&Y.charAt(0)=='0')){ System.out.println("Wrong Format"); return; } } X=s.substring(c2[count2-1]+1,c1[count2]); Y=s.substring(c1[count2]+1); x[count2]=Double.parseDouble(X); y[count2]=Double.parseDouble(Y); if((X.length()>2&&X.charAt(1)=='0')||(X.length()==2&&X.charAt(0)=='0')){ System.out.println("Wrong Format"); return; } if((Y.length()>2&&Y.charAt(1)=='0')||(Y.length()==2&&Y.charAt(0)=='0')){ System.out.println("Wrong Format"); return; } double reson=Math.sqrt((Math.pow((double)(x[0]-x[1]), 2.0)+Math.pow((double)(y[0]-y[1]), 2.0))*1.0); System.out.println(reson); in.close(); }
这里就是比较朴实的提取数字并且计算答案了,其中也夹杂了对"005"、"00"这种错误格式的判定。除去前两个和最后两个,每组都是空格到逗号间有一个,逗号到空格间又有一个,然后先用X或Y来存这段字符串,再判断这段字符串是否前两位都位非数字,通过后则用下x[i]或y[i]储存起来,用以计算2点距离。
2.第三次作业:
类图:
判断格式错误与数据错误的方法和7-1差不多,多了一点前缀的判定,判定第一位是否是数字,判定第二位是否为冒号。但是我觉得格式判断比7-1精确了许多,7-1满分的格式判断在7-2不是满分,7-1那一点有些取巧的思路没经过优化在7-2直接是无了。
if(s.length()<5){ System.out.println("Wrong Format"); return; } if(s.charAt(0)<'0'||s.charAt(0)>'9'){ System.out.println("Wrong Format"); return; } if(s.charAt(1)!=':'){ System.out.println("Wrong Format"); return; }
7-1只用算2点距离,代码量小直接放到一起了,而7-2需要进行的运算很多,所以把运算单独放到了一个方法里。
public void line(String s){ double k=0,d=0,b=0; double x0=0,y0=0;//交点坐标 double k1,k2,b1,b2; int i,j; boolean bool,end=false; int count=(Integer.parseInt(s.substring(0,1))+4)/2; for(i=0;i<count-1;i++){ for(j=i+1;j<count;j++) if(x[i]==x[j]) if(y[i]==y[j]) end=true; if(end==true) break; } if(end==true) System.out.println("points coincide"); else{ switch(s.charAt(0)){ case '1': if(x[1]-x[0]==0) System.out.println("Slope does not exist"); else{ k=(y[1]-y[0])/(x[1]-x[0]); System.out.println(k); } break; case '2': if(x[1]-x[2]==0) d=Math.abs(x[0]-x[1]); else{ k=(y[1]-y[2])/(x[1]-x[2]); b=y[1]-k*x[1]; d=Math.abs(k*x[0]-y[0]+b)/Math.sqrt(k*k+1); } System.out.println(d); break; case '3': if((x[1]-x[0])*(y[2]-y[1])-(x[2]-x[1])*(y[1]-y[0])==0) System.out.println("true"); else System.out.println("false"); break; case '4': if((x[1]-x[0])*(y[3]-y[2])-(x[3]-x[2])*(y[1]-y[0])==0) System.out.println("true"); else System.out.println("false"); break; case '5': if(x[1]-x[0]==0&&x[3]-x[2]==0) System.out.println("is parallel lines,have no intersection point"); else if(x[1]-x[0]!=0&&x[3]-x[2]!=0) if((y[1]-y[0])/(x[1]-x[0])==(y[3]-y[2])/(x[3]-x[2])) System.out.println("is parallel lines,have no intersection point"); else{ k1=(y[1]-y[0])/(x[1]-x[0]); k2=(y[3]-y[2])/(x[3]-x[2]); b1=y[1]-k1*x[1]; b2=y[3]-k2*x[3]; x0=(b2-b1)/(k1-k2); y0=k1*x0+b1; if((x0>Math.min(x[0],x[1])&&x0<Math.max(x[0],x[1])&&y0>Math.min(y[0],y[1])&&y0<Math.max(y[0],y[1]))||(x0>Math.min(x[2],x[3])&&x0<Math.max(x[2],x[3])&&y0>Math.min(y[2],y[3])&&y0<Math.max(y[2],y[3]))) bool=true; else bool=false; System.out.println(x0+","+y0+" "+bool); } break; } } }
计算平行以及垂直关系都是用向量方法,分别是x1y2+x2y1=0以及x1x2+y1y2=0,此方法比计算斜率更好,避免了更可能出错的分情况讨论,也减少了运算量。而计算点与直线的距离则应用了公式|Ax^2+Bx+C|/sqrt(A*A+B*B),所以这里要算k,然后转化系数A、B、C。至于求两条直线的交点好像是有一个公式可以求,但我用的还是比较朴实的二元一次方程组,直接用x、y来表示k、b(A、B、C),然后通过交点x、y的位置判断是否在两条直线内。
for(i=0;i<count-1;i++){ for(j=i+1;j<count;j++) if(x[i]==x[j]) if(y[i]==y[j]) end=true; if(end==true) break; } if(end==true) System.out.println("points coincide");
在所有判定前,这段代码是找出是否存在任意两点重合,所有之后的判定都在这个if对应的else后。
3.第三次作业7-3:
因为前两个题搞的心态炸裂所以没写第三题,但是也有写思路,这里就不上代码直接说了。格式问题和数据问题与之前大同小异,想必判定数据精确度和7-2应该差不多,但还是比第一高。形状判断和重心之类的计算都是常规数学问题,直接带公式就行了,而判断是否是钝角三角形就计算三个角大小进行判断即可,重要的是第四点以及第五点。
第四点:判断直线是否经过三角形就是分别计算直线与三边是否有交点,有则算出坐标,在此之前必须要判断直线与边的所在直线是否重合。而交点等于2时分割出的图形必然有一块是三角形,既然是计算机,那么就完全可以使用海伦公式这种公式简单但运算量大的方法来计算大三角形面积和分割后小三角形面积,两者相减即可得出另一分割图形面积。
第五点:题目中已经有了提示,随便向一个方向发出射线然后再计算,但首先要判断点是否在边上。如果点不在边上,可以先视为一条直线,然后求交点,再看所求交点是否在初定方向的那一段以排除,用最后剩下的交点来判断点是否在三角形内部。
(3)踩坑心得:
1.第一次作业:我觉得第一次作业总体应该没有什么坑,实在是题目有点问题,如果按照题目意思进行边界判定就会出错,数据判定比题目精确度第反而才能对,如果这些算坑那真的是太坑了。一开始我还以为是数据界定特别精确或者严苛到具体数位,觉得这题目很刁钻啊,后来发现只能说体验极差。
2.第二次作业:第二次作业感觉也没有很多坑,要说有的话那就是7-2中一定要注意一次是判定一组数据,所以i(假设使用i循环)要加11,直接判定下一组;如果i++就可能会出现2组数据5次判定5次输出。
3.第三次作业:这次的坑就多了,有一些地方我知道我踩了但就是不知到踩哪里了。首先这次的运算量就很大,情况也多,其次选的问题也是那种很容易漏解的问题,一不小心就容易漏掉某些答案,或者是if、else没有排除所有情况。
踩坑代码被修改了,就直接说明吧,比如判断平行就得考虑k无穷大,要单独列出来,还得考虑是否重合(第三题),再排除一堆情况,最后else出来的才是对的,做题时我就漏掉了k不存在这种情况。而k不存在这种情况在这种题型中非常喜欢考,比如说点到垂直x轴直线距离、判断平行、判断是否在同一直线上。做题是在k不存在这里踩的那是有点多。
踩的另一波坑就是关于交点是否在两条直线内的判定,一开始以为是&&的关系,后来经过样例测试才知道是||的关系,只要还在其中一条线段内就可。
(4)改进建议:
1.正则表达式还可以再细致一点,有2个特判总是过不了,代码的模块化和结构化有待提高,类与类之间的使用还有写生疏。
2.第二次作业:
(5)总结:
1.学到了什么:第一次作业让我初步熟悉了Java语法,熟悉了Java的输入输出计算等,但此时的Java还只是C换了层皮,本质没有多大不同;第二次则开始则加强了对String的了解与使用,感受到了String相比字符数组的进步与便利,而String类的各种方法也然我初步接触了对象与类;第三次我觉得就是开始加强对类或者方法的使用了,因为第一题的格式判断在后两题都要运用,估计是暗示我们把第一题的代码改良成一个类或方法以让后两题使用,但应为功能只有不多,所以更偏向方法的使用,而功能多起来时显然包装成类更加合适。
2.改进意见:这个题目本身我觉得判定数据要做好,不能出现第一次作业那种情况;
题目难度我觉得得合理一点,比如说7-3这个就太难了,数据运算多,考察的点也多,而且也不说明错误点,很难修改,到头来其实没学到啥,全在改数学错误;
我觉得题目应该更多地考察我们对于Java语言新知识的应用,对于这种数据或者数学问题没有必要抓这么紧,比如可以出点题目要求多个类之间的相互应用,类本身可以不那么复杂,但多个类的 使用肯定能让我们更多地了解到类的妙处;
实验的话希望要求表达地清晰一点,有的时候有点难以理解实验要求。
标签:charAt,tool,BLOG,length,&&,println,out 来源: https://www.cnblogs.com/uncley/p/16387502.html