华为OD机试真题---找终点

华为OD机试真题“找终点”是一道考察算法思维和编程能力的题目。题目大意是给定一个正整数数组,要求从数组的第一个元素开始,通过每一步跳跃(跳跃步数由当前所在元素的值决定)到达数组的最后一个元素,并计算最少的步骤数。如果无法到达数组的最后一个元素,则返回-1。

题目描述

  • 输入:一个正整数数组,数组长度小于100,数组中的元素代表从当前位置可以跳跃的步数。
  • 输出:最少的步骤数,如果无法到达终点则返回-1。

解题思路

  1. 初始化

    • 创建一个数组来存储正整数。
    • 初始化一个变量来记录最小步数,初始值可以设置为一个较大的数(如数组长度加1,以便后续判断是否可达)。
  2. 遍历第一步的步长

    • 由于第一步的步长必须在1到数组长度的一半之间(包括1但不包括数组长度的一半),因此需要对这个范围内的步长进行遍历。
  3. 尝试到达终点

    • 对于每个可能的第一步步长,从数组的第一个元素开始,按照当前元素的值进行跳跃,直到无法继续跳跃或到达终点。
    • 在跳跃过程中,记录步数,并在每次跳跃后更新当前位置。
  4. 判断并更新最小步数

    • 如果在某次跳跃中成功到达终点,则比较当前步数与之前记录的最小步数,并更新最小步数(如果更小的话)。
  5. 输出结果

    • 遍历完所有可能的第一步步长后,检查最小步数是否仍然保持为初始值(即未找到可达路径),如果是,则输出-1;否则,输出最小步数。

示例

输入7 5 9 4 2 6 8 3 5 4 3 9

输出2(第一步跳5步到第二个元素9,第二步从9开始跳9步到达终点)

注意事项

  • 题目要求的是最少的步骤数,因此需要遍历所有可能的第一步步长来找到最优解。
  • 如果数组中的某个元素值为0,且该元素不是最后一个元素,则可能无法从该元素继续跳跃,需要特别注意这种情况。
  • 在编程实现时,要注意数组越界的问题,确保在跳跃过程中不会访问到数组范围之外的元素。

编程实现(示例代码,以Java为例)


import java.util.Arrays;
import java.util.List;

public class FindFinish {
    public static void main(String[] args) {

        List<Integer> nums = Arrays.asList(7, 5, 9, 4, 2, 6, 8, 3, 5, 4, 3, 9);

        int result = findFinish(nums);
        System.out.println("最小步数:"+result);
    }

    public static int findFinish(List<Integer> nums) {
        int n = nums.size();
        if (n == 0) return -1;

        int minSteps = n + 1; // 初始化为一个较大的数

        for (int firstStep = 1; firstStep < n / 2; firstStep++) {
            int steps = 1; // 记录步数,第一步已经迈出
            int currentIndex = firstStep;

            while (currentIndex < n) {
                currentIndex += nums.get(currentIndex);
                steps++;
                if (currentIndex == n - 1) {
                    minSteps = Math.min(minSteps, steps);
                    break;
                }
            }
        }

        return minSteps == n + 1 ? -1 : minSteps;
    }
}

注意:上述代码虽然能实现题目要求,输出最小步数。但仔细分析就会发现代码其实是有问题的。

潜在问题及修改建议:

1、数组越界问题:在循环中 currentIndex += nums.get(currentIndex) 可能导致数组越界。如果nums.get(currentIndex) 的值非常大,currentIndex 可能会超过 n - 1,从而导致 List 越界访问。

  • 修改建议:在每次增加 currentIndex 前,先检查是否越界。

2、逻辑 Bug:当 firstStep 设置为 n / 2 时,可能会错过某些可能的路径。虽然题目没有明确说明,但从逻辑上讲,firstStep 应该遍历到 n-1 才能覆盖所有可能的情况。

  • 修改建议:将 for 循环条件改为 firstStep <= n - 1。

优化方向及修改建议:

1、初始化 minSteps 的值:初始值 n + 1 可以简化为 Integer.MAX_VALUE,这样更直观且不容易出错。

  • 修改建议:使用 Integer.MAX_VALUE 初始化 minSteps。

2、提高代码可读性:通过添加注释来提高代码的可读性和维护性。

  • 修改建议:在关键逻辑处添加注释。

3、减少不必要的循环次数:在 while 循环内部,如果 currentIndex 超过 n - 1,则可以直接跳出循环,避免无意义的计算。

  • 修改建议:在 while 循环内部添加判断条件。

以下是修改后的代码:

public static int findFinish(List<Integer> nums) {
    int n = nums.size();
    if (n == 0) return -1;

    int minSteps = Integer.MAX_VALUE; // 初始化为一个极大的数

    // 遍历所有可能的第一步
    for (int firstStep = 1; firstStep <= n - 1; firstStep++) {
        int steps = 1; // 记录步数,第一步已经迈出
        int currentIndex = firstStep;

        // 当前索引不超过数组长度时继续计算
        while (currentIndex < n) {
            // 防止数组越界
            if (currentIndex + nums.get(currentIndex) >= n) {
                break;
            }
            
            currentIndex += nums.get(currentIndex);
            steps++;

            if (currentIndex == n - 1) {
                minSteps = Math.min(minSteps, steps);
                break;
            }
        }
    }

    return minSteps == Integer.MAX_VALUE ? -1 : minSteps;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值