BLOG3
BLOG-3
前言:对于这三次的题目集难度评价为第一次难度较为大,但依照老师题中所给的类图编写代码,难度相对降低了不少,后面两次也逐渐简单,耗费的时间也相比第一次少了不少,这几次题目集的数量较少,基本为两到三道题。题目中所用到的主要知识点为容器的存储与输出,同时还有正则表达式的运用及Date类里面方法的使用和Date类型转化为long类型进行计算,利用接口排序的方法。对于题目的考虑需要经过多次思考。这些问题都很有难度,很锻炼大家的设计能力,思维方式。
设计与分析:
题目为电信计费系列的问题。
最后一行以“end”结束:用以下代码来判断
while (!str.equals("end"))
座机呼叫座机:t-主叫号码 接听号码 起始时间 结束时间(t-079186330022 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:11)判断此类所使用的代码为:
str.matches("t-(\\d){11,12}\\s(\\d){10,12}\\s((((1[6-9]|[2-9]\\d)\\d{2}).([13578]|1[02]).([1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2}).([13456789]|1[012]).([1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-2-([1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-2-29-)) (20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\s((((1[6-9]|[2-9]\\d)\\d{2}).([13578]|1[02]).([1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2}).([13456789]|1[012]).([1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-2-([1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-2-29-)) (20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d")
后面长的为判断输入年份的合法性以及规范性。
采用循环对数据进行比对,并对其进行容器的存储,代码过长,便取其中一段,代码如下:
if(users.get(i).number.equals(string[0])){
if(string[1].startsWith("0791")){
users.get(i).userRecords.addCallingInCityRecords(new CallRecord(string[2]+" "+string[3],string[4]+" "+string[5]));
users.get(i).setUserRecords(users.get(i).userRecords);
}
else if(string[1].substring(0,4).matches("(079\\d|0701)"
)){
users.get(i).userRecords.addCallingInProvinceRecords(new CallRecord(string[2]+" "+string[3],string[4]+" "+string[5]));
users.get(i).setUserRecords(users.get(i).userRecords);
}
else{
users.get(i).userRecords.addCallingInLandRecords(new CallRecord(string[2]+" "+string[3],string[4]+" "+string[5]));
users.get(i).setUserRecords(users.get(i).userRecords);
}if(users.get(i).number.equals(string[0])){
if(string[1].startsWith("0791")){
users.get(i).userRecords.addCallingInCityRecords(new CallRecord(string[2]+" "+string[3],string[4]+" "+string[5]));
users.get(i).setUserRecords(users.get(i).userRecords);
}
else if(string[1].substring(0,4).matches("(079\\d|0701)"
)){
users.get(i).userRecords.addCallingInProvinceRecords(new CallRecord(string[2]+" "+string[3],string[4]+" "+string[5]));
users.get(i).setUserRecords(users.get(i).userRecords);
}
else{
users.get(i).userRecords.addCallingInLandRecords(new CallRecord(string[2]+" "+string[3],string[4]+" "+string[5]));
users.get(i).setUserRecords(users.get(i).userRecords);
}
对输入数据进行排序,并从大到小输出,采用user类使用接口的方法进行排序,输出的时候使用拉姆达表达式,具体如下:
class User implements Comparable<User>{
public int compareTo(User o) {
return this.getNumber().compareTo(o.getNumber());
}
}
List<User> templist = new ArrayList<>(users);
Collections.sort(templist);
for (User a:templist){
System.out.print(a.getNumber()+" ");
System.out.print(new DecimalFormat("0.0#").format(a.calCost()));
System.out.print(" ");
System.out.print(new DecimalFormat("0.0#").format(a.calBalance()));
System.out.println();
}
Date类型计算时间,将其进行类型转换计算秒:
for (CallRecord e: callRecords){
minutes = (int) Math.ceil((double) (e.getEndTime().getTime()-e.getStartTime().getTime())/ (double) 60000);
cost += 0.3*minutes;}
以上为第一次写电信计费系列的问题的分析,类图如下:


第二次电信计费系列的问题分析:
相比第一次相对复杂,但有了第一次的编写,也使本题难度下降,大体设计与第一题差距不大。但对于第一次加了几种计算价格的类方法。如下
class ReceptionPhoneInLandRoamRule extends CallChargeRule {//接电话
public double calCost(ArrayList<CallRecord> callRecords) {
double money = 0.3;
double cost = 0;
double minutes;
for (CallRecord e : callRecords) {
minutes = (int) Math.ceil((double) (e.getEndTime().getTime() - e.getStartTime().getTime()) / (double) 60000);
cost += money * minutes;
}
return cost;
}
}
等等
其次判断时间合法的方法进行了改变,将时间分割出来,使用之前判断年份合法的类使用进来,具体操作如下:
String[] str1 = string[4].split("\\.");
String[] str2 = string[5].split("\\:");
String[] str3 = string[6].split("\\.");
String[] str4 = string[7].split("\\:");
DateUtil dateUtil = new DateUtil(str1[0], str1[1], str1[2], str2[0], str2[1], str2[2]);
DateUtil dateUtil1 = new DateUtil(str3[0], str3[1], str3[2], str4[0], str4[1], str4[2]);
class DateUtil {
int year;
int month;
int day;
int hour;
int minute;
int second;
public DateUtil(String year, String month, String day, String hour, String minute, String second) {
super();
this.year = Integer.parseInt(year);
this.month = Integer.parseInt(month);
this.day = Integer.parseInt(day);
this.hour = Integer.parseInt(hour);
this.minute = Integer.parseInt(minute);
this.second = Integer.parseInt(second);
}
public boolean checkInputValidity() {//检测输入的年、月、日是否合法
boolean b;
int[] a = new int[]{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (isLeapYear(year))
a[2] = 29;
b = (year <= 9999 && year >= 1 && month <= 12 && month >= 1 && day >= 1 && day <= a[month] && hour <= 24 && hour >= 0 && minute <= 60 && minute >= 0 && second <= 60 && second >= 0);
return b;
}
public boolean isLeapYear(int year) {//判断year是否为闰年
boolean a;
a = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0);
return a;
}
}
类图大体上也与第一次相似。
第三次电信计费系列的问题分析:
对于消息的计算,先将每次的消息存入容器内,再在容器对消息进行汇总并进行相应钱数的计算,代码如下:
class SendMessageRule{
public double calCost(ArrayList<MessageRecord> messageRecords) {
double money = 0 ;
double cost = 0;
double costs = 0;
double num = 0;
int nums = 0;
for (MessageRecord e:messageRecords){
num = e.message.length()/10.0;
if(num%1!=0)
num = num+1;
nums = nums+(int)num;
}
if(nums<=3){
money = 0.1*nums;
}
else if(nums<=5){
money = 0.2*(nums-3)+0.1*3;
}
else
money = 0.7+0.3*(nums-5);
return money;
}
}
判断分割发生了适当改变:
if (str.matches("m-1\\d{10} 1\\d{10} (\\w|\\,|\\.| )+")||str.matches("m-1\\d{10} 1\\d{10}")){
string = str.substring(2, str.length()).split("\\s");
String message = str.substring(26, str.length());
for (int i = 0; i < users.size(); i++) {
if (users.get(i).number.equals(string[0])) {
users.get(i).userRecords.addSendMessageRecord(new MessageRecord(message));
}
}
}
str = input.nextLine();
}
其余方式未发生改变
类图如下:

把重复的同学信息删掉,只保留一个
输入格式:
第一行输入一个N,代表C~K导出的名单共有N行(N<100000).
接下来的N行,每一行包括一个同学的信息,学号 姓名 年龄 性别。
输出格式:
第一行输出一个n,代表删除重复名字后C~K的班级共有几人。
接下来的n行,输出每一个同学的信息,输出按照学号从小到大的顺序。
// 1、导入相关包
import javax.swing.text.html.HTMLDocument;
import java.util.*;
//定义员工类
class Students implements Comparable<Students>{
String id;
private String name;
private int age;
String gender;
public Students() {
super();
}
public Students(String id,String name, int age, String gender) {
super();
this.id = id;
this.gender = gender;
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int compareTo(Students o) {
return this.getId().compareTo(o.getId());
}
}
//主函数
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
ArrayList<Students> c = new ArrayList<>();
int n = sc.nextInt();
int j = 0;
for (int i = 0; i < n; i++) {
String ID = sc.next();
String Name = sc.next();
int Age = sc.nextInt();
String Gender = sc.next();
Students student = new Students(ID,Name, Age,Gender);
for(int k=0;k<c.size();k++){
if(Objects.equals(c.get(k).getId(),student.getId()))
j=1;
}
if(j==0)
c.add(student);
j=0;
}
System.out.println(c.size());
List<Students> templist = new ArrayList<>(c);
Collections.sort(templist);
for (Students a:templist){
System.out.println(a.getId()+" "+a.getName()+" "+a.getAge()+" "+a.getGender());
}
}
}
踩坑心得:
一开始对年份未判断,导致大部分非法输入的测试点未过,但在网上直接搜索到年份正则表达式的判断便使这些测试点都通过了。
第二题中对于年份的判断使用第一题的,在一月到二月的跨月时的计算会发生计算错误,所以我将时间单独拿出来判断。
第三题计算钱数的想法错误,以为1-3条时每条0.1元,3-5条时0.2元,超过5条0.3元,后发现想法错误,并进行修改过后便通过了。
写一个类Shop(商店)、内部类InnerCoupons(内部购物券)这道题时,算价格直接放在输出里计算导致每次都从50开始,后将其提到输出前面便计算正常了。
改进建议:
编写代码时应逻辑缜密。
应每次题目集都是迭代式,所以在编写代码时应尽可能保持代码的可拓展性。
总结:
我大致了解了容器的使用,以及跨类型计算时间,作业基本上都是迭代作业,这也体现了Java的可复用性和扩展型,只要代码的考虑的完全,进行迭代便会简单许多。接口和抽象类一个重要的区别就是接口中只有抽象方法和常量,但接口可以进行多继承。

浙公网安备 33010602011771号