1. 题目解析与解题思路
这道题目来自GESP一级考试,考察的是基础的编程逻辑和条件判断能力。题目描述了一个非常生活化的场景:Alice想在自己班上找一位身高最接近自己的小朋友交朋友。如果有多个小朋友的身高差距相同,她会选择其中较矮的那位。
1.1 题目核心要求
题目给出了四个小朋友的身高(H1-H4),其中H1是Alice自己的身高。我们需要:
- 计算其他三位小朋友与Alice的身高差绝对值
- 找出差值最小的那个小朋友
- 如果有多人差值相同,选择其中身高较矮的那位
1.2 输入输出分析
输入格式非常明确:四行整数,分别代表四个小朋友的身高。输出只需要一个整数,即符合条件的朋友的身高。
题目还给出了数据范围的保证:
- 所有身高都在100到199之间
- 所有身高互不相同
这个保证很重要,它意味着:
- 我们不需要处理负数或特别大的数值
- 不需要考虑有多个小朋友身高完全相同的情况
2. 解题步骤详解
2.1 基本思路
解决这个问题的基本思路可以分为以下几个步骤:
- 读取四个小朋友的身高(h1, h2, h3, h4)
- 计算h2、h3、h4与h1的绝对差值
- 比较这三个差值,找出最小的那个
- 如果有多个差值相同,选择身高较小的那个
- 输出最终结果
2.2 变量设计
在实现这个思路时,我们需要维护两个关键变量:
ad:当前最小的身高差值(初始值为第一个小朋友的差值)ans:当前最优解的身高(初始值为第一个小朋友的身高)
随着我们逐个检查其他小朋友,这两个变量会根据条件不断更新。
2.3 关键判断逻辑
对于每个后续的小朋友(h3和h4),我们需要进行两种情况的判断:
-
如果当前小朋友的差值小于
ad:- 更新
ad为当前差值 - 更新
ans为当前小朋友的身高
- 更新
-
如果当前小朋友的差值等于
ad:- 比较当前小朋友的身高和
ans - 如果当前小朋友更矮,则更新
ans
- 比较当前小朋友的身高和
注意:绝对差值的计算需要使用绝对值函数,或者手动处理负值情况。在给出的示例代码中,采用的是手动处理的方式。
3. 代码实现解析
让我们详细分析提供的C++代码实现:
cpp复制#include <iostream>
using namespace std;
int main()
{
// 定义四个存储小朋友身高的变量
int h1, h2, h3, h4;
cin >> h1 >> h2 >> h3 >> h4;
// 计算第一个小朋友的差值并初始化变量
int d = h1 - h2;
if(d < 0) {
d = -d;
}
int ad = d, ans = h2;
// 处理第二个小朋友
d = h1 - h3;
if(d < 0) {
d = -d;
}
if(ad > d || ad == d && h3 < ans) {
ad = d;
ans = h3;
}
// 处理第三个小朋友
d = h1 - h4;
if(d < 0) {
d = -d;
}
if(ad > d || ad == d && h4 < ans) {
ad = d;
ans = h4;
}
cout << ans;
return 0;
}
3.1 代码结构分析
- 输入处理:使用
cin读取四个整数,分别存储在h1-h4中 - 初始化阶段:计算h2与h1的差值,并初始化
ad和ans - 比较阶段:依次处理h3和h4,更新最优解
- 输出结果:打印最终确定的
ans
3.2 关键代码片段解析
计算绝对差值的部分:
cpp复制d = h1 - h3;
if(d < 0) {
d = -d;
}
这里手动计算了绝对值,而不是使用abs()函数。这在考试中是可行的,但实际编程中建议使用标准库函数。
条件判断部分:
cpp复制if(ad > d || ad == d && h3 < ans)
这个条件包含了两种情况:
- 当前差值更小(
ad > d) - 差值相同但身高更矮(
ad == d && h3 < ans)
4. 常见问题与优化建议
4.1 常见错误
- 忘记处理绝对值:直接使用h1-h2而不取绝对值,会导致差值计算错误
- 初始化错误:没有正确初始化
ad和ans,直接从h3开始比较 - 条件判断不完整:只考虑了差值更小的情况,忽略了差值相同但身高更矮的情况
- 输入顺序错误:误认为h1是第一个输入,实际上题目说明第i行是Hi
4.2 代码优化建议
- 使用数组存储身高:可以定义一个数组
int h[4],这样代码会更简洁,也更容易扩展 - 使用循环结构:对于更多小朋友的情况,使用循环会更高效
- 使用标准库函数:如
abs()计算绝对值,min()选择较小值 - 添加输入验证:虽然题目保证输入范围,但实际编程中可以添加检查
优化后的代码可能如下:
cpp复制#include <iostream>
#include <cstdlib> // 用于abs函数
using namespace std;
int main() {
int h[4];
for(int i = 0; i < 4; i++) {
cin >> h[i];
}
int min_diff = abs(h[0] - h[1]);
int ans = h[1];
for(int i = 2; i < 4; i++) {
int diff = abs(h[0] - h[i]);
if(diff < min_diff || (diff == min_diff && h[i] < ans)) {
min_diff = diff;
ans = h[i];
}
}
cout << ans;
return 0;
}
4.3 测试用例建议
为了验证代码的正确性,建议测试以下几种情况:
-
正常情况:有明显最接近的身高
- 输入:150, 160, 140, 170
- 预期输出:140
-
有多个相同差值的情况
- 输入:150, 140, 160, 160
- 预期输出:140(选择较矮的)
-
边界情况:接近100或199
- 输入:100, 110, 105, 120
- 预期输出:105
-
极端接近的情况
- 输入:150, 151, 149, 152
- 预期输出:149
5. 算法复杂度分析
5.1 时间复杂度
无论采用原始代码还是优化后的循环版本,算法的时间复杂度都是O(1)。因为:
- 输入大小固定(4个数字)
- 比较次数固定(3次比较)
即使使用循环结构,循环次数也是固定的(从h[1]到h[3])。对于这类固定输入规模的问题,时间复杂度分析意义不大。
5.2 空间复杂度
空间复杂度也是O(1),因为:
- 只使用了固定数量的变量(4个身高变量,加上一些临时变量)
- 不随输入规模增长而增加
6. 编程技巧与学习建议
6.1 绝对值计算的多种方式
在C++中,计算绝对值有几种方法:
- 使用
<cstdlib>中的abs()函数(适用于整数) - 使用
<cmath>中的fabs()函数(适用于浮点数) - 手动计算:
d = (d < 0) ? -d : d
6.2 条件表达式的简化
原始代码中的条件判断:
cpp复制if(ad > d || ad == d && h3 < ans)
可以进一步简化为:
cpp复制if(d < ad || (d == ad && h3 < ans))
这样更符合"小于"的直观理解。
6.3 学习建议
对于编程初学者,建议:
- 先理解问题,再动手编码
- 多画流程图或写伪代码,理清逻辑
- 注意边界条件和特殊情况
- 养成良好编码习惯(如合理命名变量、适当添加注释)
- 多测试不同情况的输入,验证代码正确性
这道题目虽然简单,但很好地训练了基础的编程思维和条件判断能力。理解并掌握这类问题的解法,对后续学习更复杂的算法很有帮助。