题目
小E的射击训练
问题描述
小E正在训练场进行射击练习,靶有10个环,靶心位于坐标(0, 0)。每个环对应不同的得分,靶心内(半径为1)得10分,依次向外的每个环分数减少1分。若射击点在某个半径为i的圆内,则得11-i分。如果射击点超出所有的环,则得0分。
根据给定的射击坐标(x, y),请计算小E的射击得分。
测试样例
样例1:
输入:
x = 1, y = 0
输出:10
样例2:
输入:
x = 1, y = 1
输出:9
样例3:
输入:
x = 0, y = 5
输出:6
样例4:
输入:
x = 3, y = 4
输出:6
问题理解
题目要求我们根据给定的射击坐标 (x, y) 计算小E的射击得分。靶心位于坐标 (0, 0),靶有10个环,每个环对应不同的得分。靶心内(半径为1)得10分,依次向外的每个环分数减少1分。如果射击点超出所有的环,则得0分。
数据结构选择
第一种,在这个问题中,我们不需要复杂的数据结构,只需要基本的数学计算和条件判断。
第二种,在第一种的情况下去改进。
算法步骤
-
计算射击点到靶心的距离:
- 使用欧几里得距离公式计算射击点
(x, y)到靶心(0, 0)的距离:
Math.sqrt(x * x + y * y)
- 使用欧几里得距离公式计算射击点
-
根据距离计算得分:
-
根据题目描述,距离在不同的范围内对应不同的得分。我们可以通过一系列的条件判断来确定得分:
- 如果
distance <= 1,得分是10。 - 如果
distance <= 2,得分是9。 - 如果
distance <= 3,得分是8。 - 以此类推,直到
distance <= 10,得分是1。 - 如果
distance > 10,得分是0。
- 如果
-
-
返回得分:
- 根据计算出的距离返回相应的得分。
public class Main {
public static int solution(int x, int y) {
// 计算射击点到靶心的距离
double distance = Math.sqrt(x * x + y * y);
// 根据距离计算得分
if (distance <= 1) {
return 10;
} else if (distance <= 2) {
return 9;
} else if (distance <= 3) {
return 8;
} else if (distance <= 4) {
return 7;
} else if (distance <= 5) {
return 6;
} else if (distance <= 6) {
return 5;
} else if (distance <= 7) {
return 4;
} else if (distance <= 8) {
return 3;
} else if (distance <= 9) {
return 2;
} else if (distance <= 10) {
return 1;
} else {
return 0;
}
}
public static void main(String[] args) {
System.out.println(solution(1, 0) == 10);
System.out.println(solution(1, 1) == 9);
System.out.println(solution(0, 5) == 6);
System.out.println(solution(3, 4) == 6);
}
}
根据前面的代码,我们还能进行优化:
-
使用循环简化判断逻辑:
- 避免多个冗长的
if-else判断,改用循环更易维护。
- 避免多个冗长的
-
避免浮点运算:
- 使用平方比较来替代
Math.sqrt,提高性能。
- 使用平方比较来替代
-
增强代码的可扩展性:
- 将环数抽象为参数,方便调整靶的层数。
以下是改进后的代码:
public class ShootingScore {
/**
* 计算射击得分
*
* @param x 射击点的 x 坐标
* @param y 射击点的 y 坐标
* @param maxRings 靶的最大环数
* @return 得分
*/
public static int calculateScore(int x, int y, int maxRings) {
int distanceSquared = x * x + y * y; // 避免浮点运算
for (int i = 1; i <= maxRings; i++) {
if (distanceSquared <= i * i) {
return maxRings + 1 - i;
}
}
return 0; // 超出最大靶环范围
}
public static void main(String[] args) {
// 测试样例
System.out.println(calculateScore(1, 0, 10)); // 10
System.out.println(calculateScore(1, 1, 10)); // 9
System.out.println(calculateScore(0, 5, 10)); // 6
System.out.println(calculateScore(3, 4, 10)); // 6
}
}
改进点解析
-
循环实现得分逻辑:
- 使用
for循环从内到外遍历靶环范围,代码更加简洁。 - 如果靶环数量增加,只需修改
maxRings参数,无需改动核心逻辑。
- 使用
-
避免浮点运算:
- 通过计算坐标点到靶心的平方距离
distanceSquared替代浮点数的平方根运算 (Math.sqrt),提升了性能。
- 通过计算坐标点到靶心的平方距离
测试结果分析
对常见场景和边界值进行了测试,验证其正确性:
- 靶心命中测试:如
(0, 0),得分为靶的最高分。 - 环边界命中测试:如
(10, 0),得分为1分。 - 超出范围测试:如
(11, 0),得分为0。
总结
通过以上步骤,我们可以清晰地理解如何计算射击得分。首先计算射击点到靶心的距离,然后根据距离的范围确定得分,最后返回得分。
学习心得
在做算法题时不要忘记,它的本质还是数学题,所以做题时先考虑数学方法,再考虑算法。