「PAT乙级真题解析」Basic Level 1054 求平均值 (问题分析+完整步骤+伪代码描述+提交通过代码)

题设给定N个实数, 要求计算平均值. 平均值的计算我们非常熟悉, 所以不会是本题的核心. 题设设定, 输入数据可能非法, 计算平均值的时候不能将非法数包括在内. 所以本题的核心是识别非法输入实数和识别合法输入实数. 由于输入可能是非数字, 且涉及到对每一位的检查, 所以用字符串形式存储输入的实数, 计算和时再转为浮点数.

#算法#数据结构#需求分析#pat考试#c语言

Table of Contents

乙级的题目训练主要用来熟悉编程语言的语法和形成良好的编码习惯和编码规范。从小白开始逐步掌握用编程解决问题。

PAT乙级BasicLevelPractice 1054

问题分析

题设给定N个实数, 要求计算平均值. 平均值的计算我们非常熟悉, 所以不会是本题的核心. 题设设定, 输入数据可能非法, 计算平均值的时候不能将非法数包括在内. 所以本题的核心是识别非法输入实数和识别合法输入实数. 由于输入可能是非数字, 且涉及到对每一位的检查, 所以用字符串形式存储输入的实数, 计算和时再转为浮点数.

数据非法的判断条件

  1. 只由"-", "."以及数字组成
  2. "."最多出现一次
  3. "-"只能出现在开头, 而且只能出现一次
  4. 小数点后的数字最多2个
  5. 输入实数的数值只能在区间[-1000, 1000]之间

完整描述步骤

  1. 获取输入: 输入实数的个数
  2. 初始化全局计数器:
    • 合法输入的个数
    • 合法输入的和
  3. 对于每一个输入的实数进行合法性检查:
    • 初始化局部计数器
      • 小数点个数计数器
      • 小数点后数字个数计算器
      • 整数部分值计数器
      • 小数部分值计数器
      • 数值合法标志位
    • 检查第一位是否是"-"或者数字
      • 如果第一位是"-", 第二位是否是数字, 其他位是否是数字或小数点(认为-0001是有效输入)
      • 如果第一位是数字, 其他位是否是数字或小数点
      • 不满足上述情况的, 为非法情况
    • 统计小数点的个数
    • 统计整数部分的值
    • 统计小数部分的值
    • 如果 小数点个数大于两个 或者 小数点后数字超过2个 或者 整数+小数的值不在区间[-1000, 1000]中, 同样认为是非法情况
    • 如果输入合法, 则:
      • 合法输入的个数+1
      • 合法输入的和加上(整数部分+小数部分)的值
    • 否则: 按照要求输出错误信息
  4. 按照要求输出:
    • 如果合法输入个数为0, 则输出"The average of 0 numbers is Undefined"
    • 如果合法输入个数为1, 则输出"The average of 1 number is " + 平均值
    • 其余情况, 则输出"The average of " + 合法输入个数 + " numbers is " + 平均值

伪代码描述

  1. get input: case_amount
  2. init global counter:
    • valid_number_amount = 0;
    • sum = 0;
  3. for each case in input:
    • init local counter:

      • integer_part_value = 0;
      • float_part_value = 0;
      • dot_amount = 0;
      • decimal_digit_amount = 0;
      • is_valid = True;
      • sign = 1;
    • for each char and index in this case:

      • if index == 0 and char != '-' and not ('0' <= char <= '9'):

        • is_valid = False;
        • break;
      • if index > 0 and char != '.' and not ('0' <= char <= '9'):

        • is_valid = False;
        • break;
      • if index == 1 and char == '.' and last char == '-':

        • is_valid = False;
        • break;
      • if index == 0 and char == '-':

        • sign = -1;
        • continue;
      • if char == '.':

        • dot_amount++;
        • continue;
      • if dot_amount == 0:

        • integer_part_value = integer_part_value * 10 + (int)(char - '0');
      • elif dot_amount == 1:

        • float_part_value = float_part_value * 10 + (int)(char - '0');
        • decimal_digit_amount++;
    • total_value = sign * integer_part_value + float_part_value * 10 ^ (-decimal_digit_amount)

    • if is_valid == False or dot_amount > 1 or decimal_digit_amount > 2 or total_value > 1000 or total_value < -1000:

      • print invalid message
    • else:

      • valid_number_amount++;
      • sum += total_value
  • if valid_number_amount == 0:
    • print("The average of 0 numbers is Undefined");
  • else if valid_number_amount == 1:
    • print("The average of 1 number is " + sum);
  • else:
    • print("The average of " + valid_number_amount + " numbers is " + sum);

【注意事项】

  1. 上述方案中考虑了"-.01"的情况, 但是测试点中没有设置这种情况的测试, 所以没有考虑这种情况的解法也可以通过。

完整提交代码

/*
# 问题分析
题设给定N个实数, 要求计算平均值. 平均值的计算我们非常熟悉, 所以不会是本题的核心.
题设设定, 输入数据可能非法, 计算平均值的时候不能将非法数包括在内.
所以本题的核心是识别非法输入实数和识别合法输入实数.
由于输入可能是非数字, 且涉及到对每一位的检查, 所以用字符串形式存储输入的实数,
计算和时再转为浮点数.
 
# 数据非法的判断条件
1. 只由"-", "."以及数字组成
2. "."最多出现一次
3. "-"只能出现在开头, 而且只能出现一次
4. 小数点后的数字最多2个
5. 输入实数的数值只能在区间[-1000, 1000]之间
 
# 完整描述步骤
1. 获取输入: 输入实数的个数
2. 初始化全局计数器:
    - 合法输入的个数
    - 合法输入的和
3. 对于每一个输入的实数进行合法性检查:
    - 初始化局部计数器
        - 小数点个数计数器
        - 小数点后数字个数计算器
        - 整数部分值计数器
        - 小数部分值计数器
        - 数值合法标志位
    - 检查第一位是否是"-"或者数字
        - 如果第一位是"-", 第二位是否是数字,
其他位是否是数字或小数点(认为-0001是有效输入)
        - 如果第一位是数字, 其他位是否是数字或小数点
        - 不满足上述情况的, 为非法情况
    - 统计小数点的个数
    - 统计整数部分的值
    - 统计小数部分的值
    - 如果 小数点个数大于两个 或者 小数点后数字超过2个 或者 整数+小数的值不在区间[-1000, 1000]中,
同样认为是非法情况
    - 如果输入合法, 则:
        - 合法输入的个数+1
        - 合法输入的和加上(整数部分+小数部分)的值
    - 否则:
        按照要求输出错误信息
4. 按照要求输出:
    - 如果合法输入个数为0, 则输出"The average of 0 numbers is Undefined"
    - 如果合法输入个数为1, 则输出"The average of 1 number is " + 平均值
    - 其余情况, 则输出"The average of " + 合法输入个数 + " numbers is " + 平均值
 
# 伪代码描述
1. get input: case_amount
2. init global counter:
    - valid_number_amount = 0;
    - sum = 0;
3. for each case in input:
    - init local counter:
        - integer_part_value = 0;
        - float_part_value = 0;
        - dot_amount = 0;
        - decimal_digit_amount = 0;
        - is_valid = True;
        - sign = 1;
    - for each char and index in this case:
        - if index == 0 and char != '-' and not ('0' <= char <= '9'):
            - is_valid = False;
            - break;
        - if index > 0 and char != '.' and not ('0' <= char <= '9'):
            - is_valid = False;
            - break;
 
        - if index == 1 and char == '.' and last char == '-':
            - is_valid = False;
            - break;
 
        - if index == 0 and char == '-':
            - sign = -1;
            - continue;
        - if char == '.':
            - dot_amount++;
            - continue;
        - if dot_amount == 0:
            - integer_part_value = integer_part_value * 10 + (int)(char - '0');
        - elif dot_amount == 1:
            - float_part_value = float_part_value * 10 + (int)(char - '0');
            - decimal_digit_amount++;
 
    - total_value = sign * integer_part_value + float_part_value * 10 ^
(-decimal_digit_amount)
    - if is_valid == False or dot_amount > 1 or decimal_digit_amount > 2 or
total_value > 1000 or total_value < -1000:
        - print invalid message
    - else:
        - valid_number_amount++;
        - sum += total_value
 
- if valid_number_amount == 0:
    - print("The average of 0 numbers is Undefined");
- else if valid_number_amount == 1:
    - print("The average of 1 number is " + sum);
- else:
    - print("The average of " + valid_number_amount + " numbers is " + sum);
 
# 【注意事项】
1. 上述方案中考虑了"-.01"的情况, 但是测试点中没有设置这种情况的测试,
所以没有考虑这种情况的解法也可以通过。
*/
 
#include <stdio.h>
 
int main() {
  int case_amount;
  scanf("%d", &case_amount);
  double sum = 0;
  int valid_number_amount = 0;
  char input[100];
  for (int i = 0; i < case_amount; i++) {
    int integer_part_value = 0;
    int float_part_value = 0;
    int dot_amount = 0, decimal_digit_amount = 0;
    int is_valid = 1, sign = 1;
    scanf("%s", input);
    for (int j = 0; input[j]; j++) {
      if (j == 0 && input[j] != '-' && !(input[j] >= '0' && input[j] <= '9')) {
        is_valid = 0;
        break;
      }
 
      if (j > 0 && input[j] != '.' && !(input[j] >= '0' && input[j] <= '9')) {
        is_valid = 0;
        break;
      }
 
      if (j == 1 && input[j] == '.' && input[0] == '-') {
        is_valid = 0;
        break;
      }
 
      if (j == 0 && input[j] == '-') {
        sign = -1;
        continue;
      }
 
      if (input[j] == '.') {
        dot_amount++;
        continue;
      }
      if (dot_amount == 0) {
        integer_part_value =
            integer_part_value * 10 + ((int)input[j] - (int)'0');
      } else if (dot_amount == 1) {
        decimal_digit_amount++;
        float_part_value = float_part_value * 10 + ((int)input[j] - (int)'0');
      }
    }
 
    double number_value =
        sign * (integer_part_value +
                float_part_value / pow(10.0, decimal_digit_amount));
 
    if (is_valid == 0 || dot_amount > 1 || decimal_digit_amount > 2 ||
        number_value > 1000 || number_value < -1000) {
      printf("ERROR: %s is not a legal number\n", input);
    } else {
      valid_number_amount++;
      sum += number_value;
    }
  }
 
  if (valid_number_amount == 0) {
    printf("The average of 0 numbers is Undefined\n");
  } else if (valid_number_amount == 1) {
    printf("The average of %d number is %.2f\n", valid_number_amount,
           sum / valid_number_amount);
  } else {
    printf("The average of %d numbers is %.2f\n", valid_number_amount,
           sum / valid_number_amount);
  }
  return 0;
}
「PAT乙级真题解析」Basic Level 1054 求平均值 (问题分析+完整步骤+伪代码描述+提交通过代码) | 生活糖果