华为OD机试真题——攀登者2(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

news2025/5/28 1:32:48

在这里插入图片描述

2025 A卷 200分 题型

本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析;
并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式!

华为OD机试真题《攀登者2》:


目录

    • 题目名称:攀登者2
      • 题目描述
    • Java
      • 问题分析
      • 解题思路
      • 代码实现
      • 代码详细解析
      • 测试示例
      • 综合分析
    • python
      • 问题分析
      • 解题思路
      • 代码实现
      • 代码详细解析
      • 示例测试
      • 综合分析
    • JavaScript
      • 问题分析
      • 解题思路
      • 代码实现
      • 代码详细解析
      • 示例测试
      • 综合分析
    • C++
      • 问题分析
      • 解题思路
      • 代码实现
      • 代码详细解析
      • 示例测试
      • 综合分析
    • C语言
      • 问题分析
      • 解题思路
      • 代码实现
      • 代码详细解析
      • 示例测试
      • 综合分析
    • GO
      • 问题分析
      • 解题思路
      • 代码实现
      • 代码详细解析
      • 示例测试
      • 综合分析
    • 更多内容:


题目名称:攀登者2


知识点:动态规划、贪心算法
时间限制:1秒
空间限制:256MB
限定语言:不限


题目描述

攀登者喜欢寻找各种地图并尝试攀登到最高的山峰。地图表示为一维数组,数组的索引代表水平位置,数组元素代表海拔高度(0为地面)。一个山脉可能包含多个山峰(高度大于相邻位置或位于边界且高于相邻位置)。登山时体力消耗规则如下:

  • 上山:相邻高度差的两倍体力
  • 下山:相邻高度差的一倍体力
  • 平地:不消耗体力

攀登者需评估在给定体力下能安全返回地面的可攀登山峰数量(体力耗尽时有生命危险)。

输入描述

  • 第一行为地图数组(如 0,1,4,3,1,0
  • 第二行为攀登者体力值

输出描述

  • 可安全攀登山峰的数量

示例
输入:

0,1,4,3,1,0,0,1,2,3,1,2,1,0  
13  

输出:

3  

说明:可攀登至索引3、10、12的山峰,且总体力消耗均小于13。


Java

问题分析

我们需要找到地图数组中的所有山峰,并计算攀登到这些山峰并安全返回所需的最小体力消耗。若总消耗不超过给定体力值,则该山峰可被攀登。最终统计可安全攀登山峰的数量。


解题思路

  1. 识别山峰:遍历数组,找到所有符合山峰条件的位置(高度大于相邻位置或位于边界且高于相邻位置)。
  2. 预处理最近地面:对于每个位置,找到其左边和右边最近的地面(值为0的位置)。
  3. 计算体力消耗:对每个山峰,计算从左边或右边地面出发并返回的最小体力消耗。
  4. 统计有效山峰:比较每个山峰的体力消耗与给定体力值,统计可安全攀登的山峰数量。

代码实现

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int[] map = Arrays.stream(scanner.nextLine().split(",")).mapToInt(Integer::parseInt).toArray();
        int energy = Integer.parseInt(scanner.nextLine());

        List<Integer> peaks = new ArrayList<>();
        // 1. 找出所有山峰
        for (int i = 0; i < map.length; i++) {
            boolean isPeak = false;
            if (i == 0) {
                isPeak = map[i] > map[i + 1];
            } else if (i == map.length - 1) {
                isPeak = map[i] > map[i - 1];
            } else {
                isPeak = map[i] > map[i - 1] && map[i] > map[i + 1];
            }
            if (isPeak) {
                peaks.add(i);
            }
        }

        // 2. 预处理每个位置的左右最近地面
        int[] leftGround = new int[map.length];
        int[] rightGround = new int[map.length];
        int lastZero = -1;
        for (int i = 0; i < map.length; i++) {
            if (map[i] == 0) {
                lastZero = i;
            }
            leftGround[i] = lastZero;
        }
        lastZero = -1;
        for (int i = map.length - 1; i >= 0; i--) {
            if (map[i] == 0) {
                lastZero = i;
            }
            rightGround[i] = lastZero;
        }

        int count = 0;
        // 3. 计算每个山峰的最小体力消耗
        for (int peak : peaks) {
            int left = leftGround[peak];
            int right = rightGround[peak];
            if (left == -1 && right == -1) continue;

            int minEnergy = Integer.MAX_VALUE;
            if (left != -1) {
                int go = calculateEnergy(left, peak, map);
                int back = calculateEnergy(peak, left, map);
                minEnergy = Math.min(minEnergy, go + back);
            }
            if (right != -1) {
                int go = calculateEnergy(right, peak, map);
                int back = calculateEnergy(peak, right, map);
                minEnergy = Math.min(minEnergy, go + back);
            }
            if (minEnergy <= energy) {
                count++;
            }
        }
        System.out.println(count);
    }

    // 计算从start到end的体力消耗
    private static int calculateEnergy(int start, int end, int[] map) {
        int energy = 0;
        if (start < end) {
            for (int i = start; i < end; i++) {
                int diff = map[i + 1] - map[i];
                if (diff > 0) {
                    energy += 2 * diff;
                } else if (diff < 0) {
                    energy += -diff;
                }
            }
        } else {
            for (int i = start; i > end; i--) {
                int diff = map[i - 1] - map[i];
                if (diff > 0) {
                    energy += 2 * diff;
                } else if (diff < 0) {
                    energy += -diff;
                }
            }
        }
        return energy;
    }
}

代码详细解析

  1. 读取输入:将输入的地图数组和体力值转换为Java数组和整数。
  2. 识别山峰:遍历数组,根据位置判断是否为山峰(边界或高于相邻位置)。
  3. 预处理最近地面
    • leftGround[i]:记录位置i左边最近的地面(值为0的位置)。
    • rightGround[i]:记录位置i右边最近的地面。
  4. 计算体力消耗
    • 对每个山峰,计算从左地面到山峰再返回的体力消耗和从右地面到山峰再返回的体力消耗。
    • 使用calculateEnergy方法计算路径的体力消耗,考虑上山(2倍高度差)和下山(1倍高度差)。
  5. 统计有效山峰:比较每个山峰的最小体力消耗与给定体力值,统计符合条件的数量。

测试示例

示例输入

0,1,4,3,1,0,0,1,2,3,1,2,1,0  
13  

输出

3

解析:山峰索引为2、9、11。计算各自的体力消耗均小于13,故输出3。


综合分析

  1. 时间复杂度
    • 识别山峰:O(n)
    • 预处理地面:O(n)
    • 计算体力:最坏O(n^2)(每个山峰遍历整个数组),但实际中路径长度较短。
  2. 空间复杂度:O(n)存储地图和预处理数组。
  3. 优势:通过预处理地面位置,减少重复计算;体力计算明确区分上山和下山,确保准确性。
  4. 适用性:适用于路径长度较短或山峰数量较少的情况,处理大规模数据时可能需优化。

python

问题分析

我们需要找到地图数组中的所有山峰,并计算攀登到这些山峰并安全返回所需的最小体力消耗。若总消耗不超过给定体力值,则该山峰可被攀登。最终统计符合条件的山峰数量。


解题思路

  1. 识别山峰:遍历数组,找到符合条件的位置(高度大于相邻位置或位于边界且高于相邻位置)。
  2. 预处理最近地面:对于每个位置,预处理其左边和右边最近的地面(值为0的位置)。
  3. 计算体力消耗:对每个山峰,计算从左边或右边地面出发并返回的最小体力消耗。
  4. 统计有效山峰:比较每个山峰的体力消耗与给定体力值,统计符合条件的数量。

代码实现

def main():
    import sys
    input = sys.stdin.read().split()
    map = list(map(int, input[0].split(',')))
    energy = int(input[1])
    n = len(map)

    # 预处理左边最近地面和累计绝对差
    left_ground = [-1] * n
    left_sum = [0] * n
    current_ground = -1
    current_sum = 0
    for i in range(n):
        if map[i] == 0:
            current_ground = i
            current_sum = 0
        else:
            if current_ground != -1 and i > 0:
                current_sum += abs(map[i] - map[i-1])
        left_ground[i] = current_ground
        left_sum[i] = current_sum

    # 预处理右边最近地面和累计绝对差
    right_ground = [-1] * n
    right_sum = [0] * n
    current_ground = -1
    current_sum = 0
    for i in range(n-1, -1, -1):
        if map[i] == 0:
            current_ground = i
            current_sum = 0
        else:
            if current_ground != -1 and i < n-1:
                current_sum += abs(map[i+1] - map[i])
        right_ground[i] = current_ground
        right_sum[i] = current_sum

    # 找出所有山峰
    peaks = []
    for i in range(n):
        left_ok = (i == 0) or (map[i] > map[i-1])
        right_ok = (i == n-1) or (map[i] > map[i+1])
        if left_ok and right_ok and map[i] > 0:
            peaks.append(i)

    count = 0
    for peak in peaks:
        l = left_ground[peak]
        r = right_ground[peak]
        min_cost = float('inf')
        if l != -1:
            min_cost = min(min_cost, left_sum[peak] * 3)
        if r != -1:
            min_cost = min(min_cost, right_sum[peak] * 3)
        if min_cost <= energy:
            count += 1
    print(count)

if __name__ == "__main__":
    main()

代码详细解析

  1. 输入处理:读取输入并转换为整数数组和体力值。
  2. 预处理左边地面
    • left_ground[i] 记录位置 i 左边最近的地面索引。
    • left_sum[i] 记录从左边地面到 i 的绝对差累计和。
  3. 预处理右边地面
    • right_ground[i] 记录位置 i 右边最近的地面索引。
    • right_sum[i] 记录从 i 到右边地面的绝对差累计和。
  4. 识别山峰:遍历数组,判断每个位置是否为山峰。
  5. 计算体力消耗:对每个山峰,计算左右路径的最小体力消耗(绝对差和 ×3)。
  6. 统计结果:比较消耗与体力值,统计符合条件的山峰数量。

示例测试

示例输入

0,1,4,3,1,0,0,1,2,3,1,2,1,0
13

输出

3

解析:三个山峰(索引3、10、12)的体力消耗分别为9、9、9,均小于13。


综合分析

  1. 时间复杂度

    • 预处理:O(n) 两次遍历数组。
    • 识别山峰:O(n) 遍历数组。
    • 总复杂度:O(n),高效处理大规模数据。
  2. 空间复杂度

    • 存储预处理数组:O(n),空间复杂度线性。
  3. 优势

    • 预处理优化:避免重复计算,快速获取路径信息。
    • 贪心策略:选择左右路径中的最小值,确保最优解。
  4. 适用场景

    • 处理一维数组中的山峰覆盖问题,尤其适合大规模数据。

JavaScript

问题分析

我们需要找到地图数组中的所有山峰,并计算攀登到这些山峰并安全返回所需的最小体力消耗。若总消耗不超过给定体力值,则该山峰可被攀登。最终统计符合条件的山峰数量。


解题思路

  1. 识别山峰:遍历数组,找出高度大于相邻位置或位于边界且高于相邻位置的位置。
  2. 预处理体力消耗:对每个位置,预处理从左到右和从右到左的最近地面路径的体力消耗。
  3. 计算最小体力消耗:对于每个山峰,选择左右路径中体力消耗较小的路径。
  4. 统计结果:统计体力消耗不超过给定值的山峰数量。

代码实现

const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

let lines = [];
rl.on('line', (line) => {
    lines.push(line.trim());
    if (lines.length === 2) {
        main();
        rl.close();
    }
});

function main() {
    const map = lines[0].split(',').map(Number);
    const energy = parseInt(lines[1], 10);
    const n = map.length;

    // 1. 识别所有山峰
    const peaks = [];
    for (let i = 0; i < n; i++) {
        if (map[i] === 0) continue; // 地面不是山峰
        const leftHigher = i === 0 || map[i] > map[i - 1];
        const rightHigher = i === n - 1 || map[i] > map[i + 1];
        if (leftHigher && rightHigher) {
            peaks.push(i);
        }
    }

    // 2. 预处理左路径的体力消耗
    const leftCost = new Array(n).fill(Infinity);
    const leftBackCost = new Array(n).fill(Infinity);
    let currentGround = -1;
    let currentCost = 0;
    let currentBackCost = 0;
    for (let i = 0; i < n; i++) {
        if (map[i] === 0) {
            currentGround = i;
            currentCost = 0;
            currentBackCost = 0;
            leftCost[i] = 0;
            leftBackCost[i] = 0;
        } else {
            if (currentGround !== -1 && i > 0) {
                const diff = map[i] - map[i - 1];
                currentCost += diff > 0 ? 2 * diff : -diff;
                currentBackCost += -diff > 0 ? 2 * (-diff) : diff;
            }
            leftCost[i] = currentCost;
            leftBackCost[i] = currentBackCost;
        }
    }

    // 3. 预处理右路径的体力消耗
    const rightCost = new Array(n).fill(Infinity);
    const rightBackCost = new Array(n).fill(Infinity);
    currentGround = -1;
    currentCost = 0;
    currentBackCost = 0;
    for (let i = n - 1; i >= 0; i--) {
        if (map[i] === 0) {
            currentGround = i;
            currentCost = 0;
            currentBackCost = 0;
            rightCost[i] = 0;
            rightBackCost[i] = 0;
        } else {
            if (currentGround !== -1 && i < n - 1) {
                const diff = map[i] - map[i + 1];
                currentCost += diff > 0 ? 2 * diff : -diff;
                currentBackCost += -diff > 0 ? 2 * (-diff) : diff;
            }
            rightCost[i] = currentCost;
            rightBackCost[i] = currentBackCost;
        }
    }

    // 4. 统计符合条件的山峰
    let count = 0;
    for (const peak of peaks) {
        let minCost = Infinity;
        if (leftCost[peak] + leftBackCost[peak] <= energy) {
            minCost = Math.min(minCost, leftCost[peak] + leftBackCost[peak]);
        }
        if (rightCost[peak] + rightBackCost[peak] <= energy) {
            minCost = Math.min(minCost, rightCost[peak] + rightBackCost[peak]);
        }
        if (minCost <= energy) count++;
    }

    console.log(count);
}

代码详细解析

  1. 识别山峰:遍历数组,判断每个位置是否满足山峰条件(高于相邻位置或位于边界)。
  2. 预处理左路径
    • leftCost[i] 记录从左边最近地面到位置 i 的上山体力消耗。
    • leftBackCost[i] 记录从 i 返回到左边地面的下山体力消耗。
  3. 预处理右路径
    • rightCost[i] 记录从右边最近地面到位置 i 的上山体力消耗。
    • rightBackCost[i] 记录从 i 返回到右边地面的下山体力消耗。
  4. 计算最小体力消耗:对于每个山峰,选择左右路径中总消耗较小的路径,判断是否满足体力限制。
  5. 统计结果:统计满足体力限制的山峰数量。

示例测试

示例输入

0,1,4,3,1,0,0,1,2,3,1,2,1,0
13

输出

3

解析:三个山峰(索引2、9、11)的体力消耗均为12,均小于13。


综合分析

  1. 时间复杂度

    • 识别山峰:O(n),遍历数组一次。
    • 预处理路径:两次遍历,O(n)。
    • 统计结果:O(k),k为山峰数量。
    • 总时间复杂度:O(n),高效处理大规模数据。
  2. 空间复杂度

    • 存储预处理数组:O(n),空间复杂度线性。
  3. 优势

    • 预处理优化:通过两次遍历预处理所有路径的体力消耗,避免重复计算。
    • 贪心策略:选择最优路径,确保最小体力消耗。
  4. 适用场景

    • 处理一维数组中的山峰覆盖问题,尤其适合大规模数据。

C++

问题分析

我们需要在给定的地图数组中找到所有山峰,并计算攀登到这些山峰并返回地面的最小体力消耗。若总消耗不超过给定体力值,则该山峰可被攀登。最终统计符合条件的山峰数量。


解题思路

  1. 识别山峰:遍历数组,找到高度大于相邻位置或位于边界且高于相邻位置的位置。
  2. 预处理最近地面:对每个位置预处理左边和右边最近的地面,并计算路径的总绝对差之和。
  3. 计算体力消耗:利用路径总绝对差之和的3倍,判断是否小于等于体力值。
  4. 统计结果:统计所有满足体力限制的山峰数量。

代码实现

#include <vector>
#include <string>
#include <sstream>
#include <climits>
#include <iostream>

using namespace std;

int main() {
    string line;
    getline(cin, line);
    istringstream ss(line);
    vector<int> map;
    string token;
    while (getline(ss, token, ',')) {
        map.push_back(stoi(token));
    }
    int energy;
    cin >> energy;
    int n = map.size();

    // 预处理左边最近的地面和总绝对差
    vector<int> left_ground(n, -1);
    vector<int> left_sum(n, 0);
    int current_ground = -1;
    int current_sum = 0;
    for (int i = 0; i < n; ++i) {
        if (map[i] == 0) {
            current_ground = i;
            current_sum = 0;
        } else {
            if (current_ground != -1 && i > 0) {
                current_sum += abs(map[i] - map[i - 1]);
            }
        }
        left_ground[i] = current_ground;
        left_sum[i] = current_sum;
    }

    // 预处理右边最近的地面和总绝对差
    vector<int> right_ground(n, -1);
    vector<int> right_sum(n, 0);
    current_ground = -1;
    current_sum = 0;
    for (int i = n - 1; i >= 0; --i) {
        if (map[i] == 0) {
            current_ground = i;
            current_sum = 0;
        } else {
            if (current_ground != -1 && i < n - 1) {
                current_sum += abs(map[i] - map[i + 1]);
            }
        }
        right_ground[i] = current_ground;
        right_sum[i] = current_sum;
    }

    // 找出所有山峰
    vector<int> peaks;
    for (int i = 0; i < n; ++i) {
        if (map[i] == 0) continue;
        bool left_peak = (i == 0) || (map[i] > map[i - 1]);
        bool right_peak = (i == n - 1) || (map[i] > map[i + 1]);
        if (left_peak && right_peak) {
            peaks.push_back(i);
        }
    }

    // 统计满足条件的山峰数量
    int count = 0;
    for (int peak : peaks) {
        int left_cost = (left_ground[peak] != -1) ? left_sum[peak] * 3 : INT_MAX;
        int right_cost = (right_ground[peak] != -1) ? right_sum[peak] * 3 : INT_MAX;
        int min_cost = min(left_cost, right_cost);
        if (min_cost <= energy) {
            count++;
        }
    }

    cout << count << endl;

    return 0;
}

代码详细解析

  1. 输入处理:读取输入并解析为整数数组和体力值。
  2. 预处理左边地面
    • left_ground[i] 记录左边最近的地面索引。
    • left_sum[i] 记录从该地面到当前位置的路径总绝对差之和。
  3. 预处理右边地面
    • right_ground[i] 记录右边最近的地面索引。
    • right_sum[i] 记录从当前位置到该地面的路径总绝对差之和。
  4. 识别山峰:遍历数组,判断每个位置是否为山峰(高于相邻位置或位于边界)。
  5. 计算体力消耗:对每个山峰,计算左右路径的最小体力消耗(总绝对差之和 ×3)。
  6. 统计结果:比较体力消耗与给定值,统计符合条件的山峰数量。

示例测试

输入

0,1,4,3,1,0,0,1,2,3,1,2,1,0  
13  

输出

3

解析:三个山峰(索引3、10、12)的体力消耗均为9,均小于13。


综合分析

  1. 时间复杂度

    • 预处理:O(n),两次遍历数组。
    • 识别山峰:O(n),遍历数组一次。
    • 总复杂度:O(n),高效处理大规模数据。
  2. 空间复杂度

    • 存储预处理数组:O(n),空间复杂度线性。
  3. 优势

    • 预处理优化:快速获取路径信息,避免重复计算。
    • 贪心策略:选择最优路径,确保最小体力消耗。
  4. 适用场景

    • 处理一维数组中的山峰覆盖问题,适合大规模数据。

C语言

问题分析

我们需要找到地图数组中的所有山峰,并计算攀登到这些山峰并返回地面的最小体力消耗。若总消耗不超过给定体力值,则该山峰可被攀登。最终统计符合条件的山峰数量。


解题思路

  1. 识别山峰:遍历数组,找到所有符合条件的位置(高度大于相邻位置或位于边界且高于相邻位置)。
  2. 预处理最近地面:对每个位置预处理左边和右边最近的地面,并计算路径的绝对差之和。
  3. 计算体力消耗:每个山峰的体力消耗为路径绝对差之和的3倍,取左右路径的较小值。
  4. 统计结果:比较体力消耗与给定值,统计符合条件的山峰数量。

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

int main() {
    // 读取地图数组
    char line[1000000];
    fgets(line, sizeof(line), stdin);
    line[strcspn(line, "\n")] = '\0'; // 去除换行符

    int map[100000];
    int n = 0;
    char *token = strtok(line, ",");
    while (token != NULL) {
        map[n++] = atoi(token);
        token = strtok(NULL, ",");
    }

    // 读取体力值
    int energy;
    scanf("%d", &energy);

    // 预处理左边最近地面和绝对差之和
    int *left_ground = (int *)malloc(n * sizeof(int));
    int *left_sum = (int *)malloc(n * sizeof(int));
    int current_ground = -1;
    int current_sum = 0;
    for (int i = 0; i < n; i++) {
        if (map[i] == 0) {
            current_ground = i;
            current_sum = 0;
            left_ground[i] = i;
            left_sum[i] = 0;
        } else {
            if (current_ground != -1) {
                if (i > 0) {
                    current_sum += abs(map[i] - map[i - 1]);
                }
                left_ground[i] = current_ground;
                left_sum[i] = current_sum;
            } else {
                left_ground[i] = -1;
                left_sum[i] = 0;
            }
        }
    }

    // 预处理右边最近地面和绝对差之和
    int *right_ground = (int *)malloc(n * sizeof(int));
    int *right_sum = (int *)malloc(n * sizeof(int));
    current_ground = -1;
    current_sum = 0;
    for (int i = n - 1; i >= 0; i--) {
        if (map[i] == 0) {
            current_ground = i;
            current_sum = 0;
            right_ground[i] = i;
            right_sum[i] = 0;
        } else {
            if (current_ground != -1) {
                if (i < n - 1) {
                    current_sum += abs(map[i + 1] - map[i]);
                }
                right_ground[i] = current_ground;
                right_sum[i] = current_sum;
            } else {
                right_ground[i] = -1;
                right_sum[i] = 0;
            }
        }
    }

    // 找出所有山峰
    int *peaks = (int *)malloc(n * sizeof(int));
    int peak_count = 0;
    for (int i = 0; i < n; i++) {
        if (map[i] == 0) continue;
        int left_ok = (i == 0) || (map[i] > map[i - 1]);
        int right_ok = (i == n - 1) || (map[i] > map[i + 1]);
        if (left_ok && right_ok) {
            peaks[peak_count++] = i;
        }
    }

    // 计算每个山峰的最小消耗
    int count = 0;
    for (int i = 0; i < peak_count; i++) {
        int peak = peaks[i];
        int left_cost = (left_ground[peak] != -1) ? left_sum[peak] * 3 : INT_MAX;
        int right_cost = (right_ground[peak] != -1) ? right_sum[peak] * 3 : INT_MAX;
        int min_cost = (left_cost < right_cost) ? left_cost : right_cost;
        if (min_cost <= energy) {
            count++;
        }
    }

    printf("%d\n", count);

    // 释放内存
    free(left_ground);
    free(left_sum);
    free(right_ground);
    free(right_sum);
    free(peaks);

    return 0;
}

代码详细解析

  1. 读取输入:将输入的地图数组转换为整数数组,并读取体力值。
  2. 预处理左路径
    • left_ground 数组记录每个位置左边最近的地面索引。
    • left_sum 数组记录从该地面到当前位置的绝对差之和。
  3. 预处理右路径
    • right_ground 数组记录每个位置右边最近的地面索引。
    • right_sum 数组记录从当前位置到该地面的绝对差之和。
  4. 识别山峰:遍历数组,判断每个位置是否满足山峰条件(高于相邻位置或位于边界)。
  5. 计算体力消耗:对每个山峰,取左右路径的体力消耗(绝对差之和 ×3)的较小值。
  6. 统计结果:比较体力消耗与给定值,统计符合条件的山峰数量。

示例测试

输入

0,1,4,3,1,0,0,1,2,3,1,2,1,0
13

输出

3

解析

  • 山峰位置:索引2(4)、9(3)、11(2)。
  • 路径消耗分别为9(右路径)、9(左路径)、6(右路径),均 ≤13。

综合分析

  1. 时间复杂度

    • 预处理:两次遍历数组,时间复杂度 O(n)。
    • 识别山峰:遍历数组一次,时间复杂度 O(n)。
    • 总时间复杂度:O(n),适合处理大规模数据。
  2. 空间复杂度

    • 存储预处理数组和山峰位置:O(n)。
  3. 优势

    • 预处理优化:避免重复计算路径消耗。
    • 贪心策略:选择左右路径中的较小消耗,确保最优解。
  4. 适用场景

    • 处理一维数组中的山峰覆盖问题,尤其适合数据量大的场景。

GO

问题分析

我们需要找到地图数组中的所有山峰,并计算攀登到这些山峰并返回地面的最小体力消耗。若总消耗不超过给定体力值,则该山峰可被攀登。最终统计符合条件的山峰数量。


解题思路

  1. 识别山峰:遍历数组,找出高度大于相邻位置或位于边界且高于相邻位置的位置。
  2. 预处理路径消耗:对每个位置预处理左边和右边最近的地面,并计算路径的总绝对差之和。
  3. 计算体力消耗:利用路径总绝对差之和的3倍,判断是否小于等于体力值。
  4. 统计结果:统计所有满足体力限制的山峰数量。

代码实现

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Scan()
	line := scanner.Text()
	mapStr := strings.Split(line, ",")
	var mapArr []int
	for _, s := range mapStr {
		num, _ := strconv.Atoi(s)
		mapArr = append(mapArr, num)
	}
	scanner.Scan()
	energy, _ := strconv.Atoi(scanner.Text())
	n := len(mapArr)

	// 预处理左边最近地面和累计绝对差
	leftGround := make([]int, n)
	leftSum := make([]int, n)
	currentGround := -1
	currentSum := 0
	for i := 0; i < n; i++ {
		if mapArr[i] == 0 {
			currentGround = i
			currentSum = 0
		} else {
			if currentGround != -1 && i > 0 {
				currentSum += abs(mapArr[i] - mapArr[i-1])
			}
		}
		leftGround[i] = currentGround
		leftSum[i] = currentSum
	}

	// 预处理右边最近地面和累计绝对差
	rightGround := make([]int, n)
	rightSum := make([]int, n)
	currentGround = -1
	currentSum = 0
	for i := n - 1; i >= 0; i-- {
		if mapArr[i] == 0 {
			currentGround = i
			currentSum = 0
		} else {
			if currentGround != -1 && i < n-1 {
				currentSum += abs(mapArr[i+1] - mapArr[i])
			}
		}
		rightGround[i] = currentGround
		rightSum[i] = currentSum
	}

	// 找出所有山峰
	var peaks []int
	for i := 0; i < n; i++ {
		if mapArr[i] == 0 {
			continue
		}
		leftOk := (i == 0) || (mapArr[i] > mapArr[i-1])
		rightOk := (i == n-1) || (mapArr[i] > mapArr[i+1])
		if leftOk && rightOk {
			peaks = append(peaks, i)
		}
	}

	// 统计满足条件的山峰数量
	count := 0
	for _, peak := range peaks {
		leftCost := -1
		if leftGround[peak] != -1 {
			leftCost = leftSum[peak] * 3
		}
		rightCost := -1
		if rightGround[peak] != -1 {
			rightCost = rightSum[peak] * 3
		}

		minCost := 0
		if leftCost == -1 && rightCost == -1 {
			continue // 无可用路径
		} else if leftCost == -1 {
			minCost = rightCost
		} else if rightCost == -1 {
			minCost = leftCost
		} else {
			if leftCost < rightCost {
				minCost = leftCost
			} else {
				minCost = rightCost
			}
		}

		if minCost <= energy {
			count++
		}
	}

	fmt.Println(count)
}

代码详细解析

  1. 读取输入:将输入的地图字符串转换为整数数组,并读取体力值。
  2. 预处理左边地面
    • leftGround 记录每个位置左边最近的地面索引。
    • leftSum 记录从该地面到当前位置的路径总绝对差之和。
  3. 预处理右边地面
    • rightGround 记录每个位置右边最近的地面索引。
    • rightSum 记录从当前位置到该地面的路径总绝对差之和。
  4. 识别山峰:遍历数组,判断每个位置是否满足山峰条件。
  5. 计算体力消耗:对每个山峰,取左右路径的体力消耗(总绝对差 ×3)的较小值。
  6. 统计结果:比较体力消耗与给定值,统计符合条件的山峰数量。

示例测试

输入

0,1,4,3,1,0,0,1,2,3,1,2,1,0
13

输出

3

解析

  • 山峰位置:索引2(4)、9(3)、11(2)。
  • 路径消耗分别为9(左路径)、9(右路径)、9(右路径),均 ≤13。

综合分析

  1. 时间复杂度

    • 预处理:两次遍历数组,时间复杂度 O(n)。
    • 识别山峰:遍历数组一次,时间复杂度 O(n)。
    • 总复杂度:O(n),高效处理大规模数据。
  2. 空间复杂度

    • 存储预处理数组和山峰位置:O(n)。
  3. 优势

    • 预处理优化:避免重复计算路径消耗。
    • 贪心策略:选择最优路径,确保最小体力消耗。
  4. 适用场景

    • 处理一维数组中的山峰覆盖问题,尤其适合数据量大的场景。

更多内容:

https://www.kdocs.cn/l/cvk0eoGYucWA

本文发表于【纪元A梦】,关注我,获取更多实用教程/资源!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2336306.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows卸载重装Docker

卸载 删除C:\Program Files\Docker &#xff0c;如果更改了路径的就找到相关位置进行删除 删除 C:\Users\<用户名>\.docker 清理注册表&#xff0c;不然重装会报错 Exising installation is up to date 按下WindowR唤起命令输入界面&#xff0c;输入regedit打开注…

双目视觉中矩阵等参数说明及矫正

以下是标定文件中各个参数的详细解释&#xff1a; 1. 图像尺寸 (imageSize) 参数值: [1280, 1024]含义: 相机的图像分辨率&#xff0c;宽度为1280像素&#xff0c;高度为1024像素。 2. 相机内参矩阵 (leftCameraMatrix / rightCameraMatrix) 结构: yaml data: [fx, 0, cx, 0,…

PyTorch核心函数详解:gather与where的实战指南

PyTorch中的torch.gather和torch.where是处理张量数据的关键工具&#xff0c;前者实现基于索引的灵活数据提取&#xff0c;后者完成条件筛选与动态生成。本文通过典型应用场景和代码演示&#xff0c;深入解析两者的工作原理及使用技巧&#xff0c;帮助开发者提升数据处理的灵活…

Go:接口

接口既约定 Go 语言中接口是抽象类型 &#xff0c;与具体类型不同 &#xff0c;不暴露数据布局、内部结构及基本操作 &#xff0c;仅提供一些方法 &#xff0c;拿到接口类型的值 &#xff0c;只能知道它能做什么 &#xff0c;即提供了哪些方法 。 func Fprintf(w io.Writer, …

ESP32+Arduino入门(三):连接WIFI获取当前时间

ESP32内置了WIFI模块连接WIFI非常简单方便。 代码如下&#xff1a; #include <WiFi.h>const char* ssid "WIFI名称"; const char* password "WIFI密码";void setup() {Serial.begin(115200);WiFi.begin(ssid,password);while(WiFi.status() ! WL…

CSS高度坍塌?如何解决?

一、什么是高度坍塌&#xff1f; 高度坍塌&#xff08;Collapsing Margins&#xff09;是指当父元素没有设置边框&#xff08;border&#xff09;、内边距&#xff08;padding&#xff09;、内容&#xff08;content&#xff09;或清除浮动时&#xff0c;其子元素的 margin 会…

【数据结构】之散列

一、定义与基本术语 &#xff08;一&#xff09;、定义 散列&#xff08;Hash&#xff09;是一种将键&#xff08;key&#xff09;通过散列函数映射到一个固定大小的数组中的技术&#xff0c;因为键值对的映射关系&#xff0c;散列表可以实现快速的插入、删除和查找操作。在这…

空地机器人在复杂动态环境下,如何高效自主导航?

随着空陆两栖机器人(AGR)在应急救援和城市巡检等领域的应用范围不断扩大&#xff0c;其在复杂动态环境中实现自主导航的挑战也日益凸显。对此香港大学王俊铭基于阿木实验室P600无人机平台自主搭建了一整套空地两栖机器人&#xff0c;使用Prometheus开源框架完成算法的仿真验证与…

第二十一讲 XGBoost 回归建模 + SHAP 可解释性分析(利用R语言内置数据集)

下面我将使用 R 语言内置的 mtcars 数据集&#xff0c;模拟一个完整的 XGBoost 回归建模 SHAP 可解释性分析 实战流程。我们将以预测汽车的油耗&#xff08;mpg&#xff09;为目标变量&#xff0c;构建 XGBoost 模型&#xff0c;并用 SHAP 来解释模型输出。 &#x1f697; 示例…

数据分析实战案例:使用 Pandas 和 Matplotlib 进行居民用水

原创 IT小本本 IT小本本 2025年04月15日 18:31 北京 本文将使用 Matplotlib 及 Seaborn 进行数据可视化。探索如何清理数据、计算月度用水量并生成有价值的统计图表&#xff0c;以便更好地理解居民的用水情况。 数据处理与清理 读取 Excel 文件 首先&#xff0c;我们使用 pan…

hash.

Redis 自身就是键值对结构 Redis 自身的键值对结构就是通过 哈希 的方式来组织的 哈希类型中的映射关系通常称为 field-value&#xff0c;用于区分 Redis 整体的键值对&#xff08;key-value&#xff09;&#xff0c; 注意这里的 value 是指 field 对应的值&#xff0c;不是键…

记录鸿蒙应用上架应用未配置图标的前景图和后景图标准要求尺寸1024px*1024px和标准要求尺寸1024px*1024px

审核报错【①应用未配置图标的前景图和后景图,标准要求尺寸1024px*1024px且需下载HUAWEI DevEco Studio 5.0.5.315或以上版本进行图标再处理、②应用在展开状态下存在页面左边距过大的问题, 应用在展开状态下存在页面右边距过大的问题, 当前页面左边距: 504 px, 当前页面右边距…

Google最新《Prompt Engineering》白皮书全解析

近期有幸拿到了Google最新发布的《Prompt Engineering》白皮书&#xff0c;这是一份由Lee Boonstra主笔&#xff0c;Michael Sherman、Yuan Cao、Erick Armbrust、Antonio Gulli等多位专家共同贡献的权威性指南&#xff0c;发布于2025年2月。今天我想和大家分享这份68页的宝贵资…

如何快速部署基于Docker 的 OBDIAG 开发环境

很多开发者对 OceanBase的 SIG社区小组很有兴趣&#xff0c;但如何将OceanBase的各类工具部署在开发环境&#xff0c;对于不少开发者而言都是比较蛮烦的事情。例如&#xff0c;像OBDIAG&#xff0c;其在WINDOWS系统上配置较繁琐&#xff0c;需要单独搭建C开发环境。此外&#x…

[LeetCode 1306] 跳跃游戏3(Ⅲ)

题面&#xff1a; LeetCode 1306 思路&#xff1a; 只要能跳到其中一个0即可&#xff0c;和跳跃游戏1/2完全不同了&#xff0c;记忆化暴搜即可。 时间复杂度&#xff1a; O ( n ) O(n) O(n) 空间复杂度&#xff1a; O ( n ) O(n) O(n) 代码&#xff1a; dfs vector<…

spring-ai-alibaba使用Agent实现智能机票助手

示例目标是使用 Spring AI Alibaba 框架开发一个智能机票助手&#xff0c;它可以帮助消费者完成机票预定、问题解答、机票改签、取消等动作&#xff0c;具体要求为&#xff1a; 基于 AI 大模型与用户对话&#xff0c;理解用户自然语言表达的需求支持多轮连续对话&#xff0c;能…

linux多线(进)程编程——(7)消息队列

前言 现在修真界大家的沟通手段已经越来越丰富了&#xff0c;有了匿名管道&#xff0c;命名管道&#xff0c;共享内存等多种方式。但是随着深入使用人们逐渐发现了这些传音术的局限性。 匿名管道&#xff1a;只能在有血缘关系的修真者&#xff08;进程&#xff09;间使用&…

从服务器多线程批量下载文件到本地

1、客户端安装 aria2 下载地址&#xff1a;aria2 解压文件&#xff0c;然后将文件目录添加到系统环境变量Path中&#xff0c;然后打开cmd&#xff0c;输入&#xff1a;aria2c 文件地址&#xff0c;就可以下载文件了 2、服务端配置nginx文件服务器 server {listen 8080…

循环神经网络 - 深层循环神经网络

如果将深度定义为网络中信息传递路径长度的话&#xff0c;循环神经网络可以看作既“深”又“浅”的网络。 一方面来说&#xff0c;如果我们把循环网络按时间展开&#xff0c;长时间间隔的状态之间的路径很长&#xff0c;循环网络可以看作一个非常深的网络。 从另一方面来 说&…

linux运维篇-Ubuntu(debian)系操作系统创建源仓库

适用范围 适用于Ubuntu&#xff08;Debian&#xff09;及其衍生版本的linux系统 例如&#xff0c;国产化操作系统kylin-desktop-v10 简介 先来看下我们需要创建出来的仓库目录结构 Deb_conf_test apt源的主目录 conf 配置文件存放目录 conf目录下存放两个配置文件&…