刷题题目解析(三) | 豆包MarsCode AI 刷题

63 阅读4分钟

题目

小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分。

数据结构选择

第一种,在这个问题中,我们不需要复杂的数据结构,只需要基本的数学计算和条件判断。

第二种,在第一种的情况下去改进。

算法步骤

  1. 计算射击点到靶心的距离

    • 使用欧几里得距离公式计算射击点 (x, y) 到靶心 (0, 0) 的距离:
      Math.sqrt(x * x + y * y)
  2. 根据距离计算得分

    • 根据题目描述,距离在不同的范围内对应不同的得分。我们可以通过一系列的条件判断来确定得分:

      • 如果 distance <= 1,得分是10。
      • 如果 distance <= 2,得分是9。
      • 如果 distance <= 3,得分是8。
      • 以此类推,直到 distance <= 10,得分是1。
      • 如果 distance > 10,得分是0。
  3. 返回得分

    • 根据计算出的距离返回相应的得分。
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);
    }
}

根据前面的代码,我们还能进行优化:

  1. 使用循环简化判断逻辑

    • 避免多个冗长的 if-else 判断,改用循环更易维护。
  2. 避免浮点运算

    • 使用平方比较来替代 Math.sqrt,提高性能。
  3. 增强代码的可扩展性

    • 将环数抽象为参数,方便调整靶的层数。

以下是改进后的代码:

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

        
    }
}

改进点解析

  1. 循环实现得分逻辑

    • 使用 for 循环从内到外遍历靶环范围,代码更加简洁。
    • 如果靶环数量增加,只需修改 maxRings 参数,无需改动核心逻辑。
  2. 避免浮点运算

    • 通过计算坐标点到靶心的平方距离 distanceSquared 替代浮点数的平方根运算 (Math.sqrt),提升了性能。

测试结果分析

对常见场景和边界值进行了测试,验证其正确性:

  1. 靶心命中测试:如 (0, 0),得分为靶的最高分。
  2. 环边界命中测试:如 (10, 0),得分为1分。
  3. 超出范围测试:如 (11, 0),得分为0。

总结

通过以上步骤,我们可以清晰地理解如何计算射击得分。首先计算射击点到靶心的距离,然后根据距离的范围确定得分,最后返回得分。

学习心得

在做算法题时不要忘记,它的本质还是数学题,所以做题时先考虑数学方法,再考虑算法。