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

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
问题分析
我们需要找到地图数组中的所有山峰,并计算攀登到这些山峰并安全返回所需的最小体力消耗。若总消耗不超过给定体力值,则该山峰可被攀登。最终统计可安全攀登山峰的数量。
解题思路
- 识别山峰:遍历数组,找到所有符合山峰条件的位置(高度大于相邻位置或位于边界且高于相邻位置)。
- 预处理最近地面:对于每个位置,找到其左边和右边最近的地面(值为0的位置)。
- 计算体力消耗:对每个山峰,计算从左边或右边地面出发并返回的最小体力消耗。
- 统计有效山峰:比较每个山峰的体力消耗与给定体力值,统计可安全攀登的山峰数量。
代码实现
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;}
}
代码详细解析
- 读取输入:将输入的地图数组和体力值转换为Java数组和整数。
- 识别山峰:遍历数组,根据位置判断是否为山峰(边界或高于相邻位置)。
- 预处理最近地面:
leftGround[i]:记录位置i左边最近的地面(值为0的位置)。rightGround[i]:记录位置i右边最近的地面。
- 计算体力消耗:
- 对每个山峰,计算从左地面到山峰再返回的体力消耗和从右地面到山峰再返回的体力消耗。
- 使用
calculateEnergy方法计算路径的体力消耗,考虑上山(2倍高度差)和下山(1倍高度差)。
- 统计有效山峰:比较每个山峰的最小体力消耗与给定体力值,统计符合条件的数量。
测试示例
示例输入:
0,1,4,3,1,0,0,1,2,3,1,2,1,0
13
输出:
3
解析:山峰索引为2、9、11。计算各自的体力消耗均小于13,故输出3。
综合分析
- 时间复杂度:
- 识别山峰:O(n)
- 预处理地面:O(n)
- 计算体力:最坏O(n^2)(每个山峰遍历整个数组),但实际中路径长度较短。
- 空间复杂度:O(n)存储地图和预处理数组。
- 优势:通过预处理地面位置,减少重复计算;体力计算明确区分上山和下山,确保准确性。
- 适用性:适用于路径长度较短或山峰数量较少的情况,处理大规模数据时可能需优化。
python
问题分析
我们需要找到地图数组中的所有山峰,并计算攀登到这些山峰并安全返回所需的最小体力消耗。若总消耗不超过给定体力值,则该山峰可被攀登。最终统计符合条件的山峰数量。
解题思路
- 识别山峰:遍历数组,找到符合条件的位置(高度大于相邻位置或位于边界且高于相邻位置)。
- 预处理最近地面:对于每个位置,预处理其左边和右边最近的地面(值为0的位置)。
- 计算体力消耗:对每个山峰,计算从左边或右边地面出发并返回的最小体力消耗。
- 统计有效山峰:比较每个山峰的体力消耗与给定体力值,统计符合条件的数量。
代码实现
def main():import sysinput = sys.stdin.read().split()map = list(map(int, input[0].split(',')))energy = int(input[1])n = len(map)# 预处理左边最近地面和累计绝对差left_ground = [-1] * nleft_sum = [0] * ncurrent_ground = -1current_sum = 0for i in range(n):if map[i] == 0:current_ground = icurrent_sum = 0else:if current_ground != -1 and i > 0:current_sum += abs(map[i] - map[i-1])left_ground[i] = current_groundleft_sum[i] = current_sum# 预处理右边最近地面和累计绝对差right_ground = [-1] * nright_sum = [0] * ncurrent_ground = -1current_sum = 0for i in range(n-1, -1, -1):if map[i] == 0:current_ground = icurrent_sum = 0else:if current_ground != -1 and i < n-1:current_sum += abs(map[i+1] - map[i])right_ground[i] = current_groundright_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 = 0for 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 += 1print(count)if __name__ == "__main__":main()
代码详细解析
- 输入处理:读取输入并转换为整数数组和体力值。
- 预处理左边地面:
left_ground[i]记录位置i左边最近的地面索引。left_sum[i]记录从左边地面到i的绝对差累计和。
- 预处理右边地面:
right_ground[i]记录位置i右边最近的地面索引。right_sum[i]记录从i到右边地面的绝对差累计和。
- 识别山峰:遍历数组,判断每个位置是否为山峰。
- 计算体力消耗:对每个山峰,计算左右路径的最小体力消耗(绝对差和 ×3)。
- 统计结果:比较消耗与体力值,统计符合条件的山峰数量。
示例测试
示例输入:
0,1,4,3,1,0,0,1,2,3,1,2,1,0
13
输出:
3
解析:三个山峰(索引3、10、12)的体力消耗分别为9、9、9,均小于13。
综合分析
-
时间复杂度:
- 预处理:O(n) 两次遍历数组。
- 识别山峰:O(n) 遍历数组。
- 总复杂度:O(n),高效处理大规模数据。
-
空间复杂度:
- 存储预处理数组:O(n),空间复杂度线性。
-
优势:
- 预处理优化:避免重复计算,快速获取路径信息。
- 贪心策略:选择左右路径中的最小值,确保最优解。
-
适用场景:
- 处理一维数组中的山峰覆盖问题,尤其适合大规模数据。
JavaScript
问题分析
我们需要找到地图数组中的所有山峰,并计算攀登到这些山峰并安全返回所需的最小体力消耗。若总消耗不超过给定体力值,则该山峰可被攀登。最终统计符合条件的山峰数量。
解题思路
- 识别山峰:遍历数组,找出高度大于相邻位置或位于边界且高于相邻位置的位置。
- 预处理体力消耗:对每个位置,预处理从左到右和从右到左的最近地面路径的体力消耗。
- 计算最小体力消耗:对于每个山峰,选择左右路径中体力消耗较小的路径。
- 统计结果:统计体力消耗不超过给定值的山峰数量。
代码实现
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);
}
代码详细解析
- 识别山峰:遍历数组,判断每个位置是否满足山峰条件(高于相邻位置或位于边界)。
- 预处理左路径:
leftCost[i]记录从左边最近地面到位置i的上山体力消耗。leftBackCost[i]记录从i返回到左边地面的下山体力消耗。
- 预处理右路径:
rightCost[i]记录从右边最近地面到位置i的上山体力消耗。rightBackCost[i]记录从i返回到右边地面的下山体力消耗。
- 计算最小体力消耗:对于每个山峰,选择左右路径中总消耗较小的路径,判断是否满足体力限制。
- 统计结果:统计满足体力限制的山峰数量。
示例测试
示例输入:
0,1,4,3,1,0,0,1,2,3,1,2,1,0
13
输出:
3
解析:三个山峰(索引2、9、11)的体力消耗均为12,均小于13。
综合分析
-
时间复杂度:
- 识别山峰:O(n),遍历数组一次。
- 预处理路径:两次遍历,O(n)。
- 统计结果:O(k),k为山峰数量。
- 总时间复杂度:O(n),高效处理大规模数据。
-
空间复杂度:
- 存储预处理数组:O(n),空间复杂度线性。
-
优势:
- 预处理优化:通过两次遍历预处理所有路径的体力消耗,避免重复计算。
- 贪心策略:选择最优路径,确保最小体力消耗。
-
适用场景:
- 处理一维数组中的山峰覆盖问题,尤其适合大规模数据。
C++
问题分析
我们需要在给定的地图数组中找到所有山峰,并计算攀登到这些山峰并返回地面的最小体力消耗。若总消耗不超过给定体力值,则该山峰可被攀登。最终统计符合条件的山峰数量。
解题思路
- 识别山峰:遍历数组,找到高度大于相邻位置或位于边界且高于相邻位置的位置。
- 预处理最近地面:对每个位置预处理左边和右边最近的地面,并计算路径的总绝对差之和。
- 计算体力消耗:利用路径总绝对差之和的3倍,判断是否小于等于体力值。
- 统计结果:统计所有满足体力限制的山峰数量。
代码实现
#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;
}
代码详细解析
- 输入处理:读取输入并解析为整数数组和体力值。
- 预处理左边地面:
left_ground[i]记录左边最近的地面索引。left_sum[i]记录从该地面到当前位置的路径总绝对差之和。
- 预处理右边地面:
right_ground[i]记录右边最近的地面索引。right_sum[i]记录从当前位置到该地面的路径总绝对差之和。
- 识别山峰:遍历数组,判断每个位置是否为山峰(高于相邻位置或位于边界)。
- 计算体力消耗:对每个山峰,计算左右路径的最小体力消耗(总绝对差之和 ×3)。
- 统计结果:比较体力消耗与给定值,统计符合条件的山峰数量。
示例测试
输入:
0,1,4,3,1,0,0,1,2,3,1,2,1,0
13
输出:
3
解析:三个山峰(索引3、10、12)的体力消耗均为9,均小于13。
综合分析
-
时间复杂度:
- 预处理:O(n),两次遍历数组。
- 识别山峰:O(n),遍历数组一次。
- 总复杂度:O(n),高效处理大规模数据。
-
空间复杂度:
- 存储预处理数组:O(n),空间复杂度线性。
-
优势:
- 预处理优化:快速获取路径信息,避免重复计算。
- 贪心策略:选择最优路径,确保最小体力消耗。
-
适用场景:
- 处理一维数组中的山峰覆盖问题,适合大规模数据。
C语言
问题分析
我们需要找到地图数组中的所有山峰,并计算攀登到这些山峰并返回地面的最小体力消耗。若总消耗不超过给定体力值,则该山峰可被攀登。最终统计符合条件的山峰数量。
解题思路
- 识别山峰:遍历数组,找到所有符合条件的位置(高度大于相邻位置或位于边界且高于相邻位置)。
- 预处理最近地面:对每个位置预处理左边和右边最近的地面,并计算路径的绝对差之和。
- 计算体力消耗:每个山峰的体力消耗为路径绝对差之和的3倍,取左右路径的较小值。
- 统计结果:比较体力消耗与给定值,统计符合条件的山峰数量。
代码实现
#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;
}
代码详细解析
- 读取输入:将输入的地图数组转换为整数数组,并读取体力值。
- 预处理左路径:
left_ground数组记录每个位置左边最近的地面索引。left_sum数组记录从该地面到当前位置的绝对差之和。
- 预处理右路径:
right_ground数组记录每个位置右边最近的地面索引。right_sum数组记录从当前位置到该地面的绝对差之和。
- 识别山峰:遍历数组,判断每个位置是否满足山峰条件(高于相邻位置或位于边界)。
- 计算体力消耗:对每个山峰,取左右路径的体力消耗(绝对差之和 ×3)的较小值。
- 统计结果:比较体力消耗与给定值,统计符合条件的山峰数量。
示例测试
输入:
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。
综合分析
-
时间复杂度:
- 预处理:两次遍历数组,时间复杂度 O(n)。
- 识别山峰:遍历数组一次,时间复杂度 O(n)。
- 总时间复杂度:O(n),适合处理大规模数据。
-
空间复杂度:
- 存储预处理数组和山峰位置:O(n)。
-
优势:
- 预处理优化:避免重复计算路径消耗。
- 贪心策略:选择左右路径中的较小消耗,确保最优解。
-
适用场景:
- 处理一维数组中的山峰覆盖问题,尤其适合数据量大的场景。
GO
问题分析
我们需要找到地图数组中的所有山峰,并计算攀登到这些山峰并返回地面的最小体力消耗。若总消耗不超过给定体力值,则该山峰可被攀登。最终统计符合条件的山峰数量。
解题思路
- 识别山峰:遍历数组,找出高度大于相邻位置或位于边界且高于相邻位置的位置。
- 预处理路径消耗:对每个位置预处理左边和右边最近的地面,并计算路径的总绝对差之和。
- 计算体力消耗:利用路径总绝对差之和的3倍,判断是否小于等于体力值。
- 统计结果:统计所有满足体力限制的山峰数量。
代码实现
package mainimport ("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 []intfor _, 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 := -1currentSum := 0for i := 0; i < n; i++ {if mapArr[i] == 0 {currentGround = icurrentSum = 0} else {if currentGround != -1 && i > 0 {currentSum += abs(mapArr[i] - mapArr[i-1])}}leftGround[i] = currentGroundleftSum[i] = currentSum}// 预处理右边最近地面和累计绝对差rightGround := make([]int, n)rightSum := make([]int, n)currentGround = -1currentSum = 0for i := n - 1; i >= 0; i-- {if mapArr[i] == 0 {currentGround = icurrentSum = 0} else {if currentGround != -1 && i < n-1 {currentSum += abs(mapArr[i+1] - mapArr[i])}}rightGround[i] = currentGroundrightSum[i] = currentSum}// 找出所有山峰var peaks []intfor 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 := 0for _, peak := range peaks {leftCost := -1if leftGround[peak] != -1 {leftCost = leftSum[peak] * 3}rightCost := -1if rightGround[peak] != -1 {rightCost = rightSum[peak] * 3}minCost := 0if 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)
}
代码详细解析
- 读取输入:将输入的地图字符串转换为整数数组,并读取体力值。
- 预处理左边地面:
leftGround记录每个位置左边最近的地面索引。leftSum记录从该地面到当前位置的路径总绝对差之和。
- 预处理右边地面:
rightGround记录每个位置右边最近的地面索引。rightSum记录从当前位置到该地面的路径总绝对差之和。
- 识别山峰:遍历数组,判断每个位置是否满足山峰条件。
- 计算体力消耗:对每个山峰,取左右路径的体力消耗(总绝对差 ×3)的较小值。
- 统计结果:比较体力消耗与给定值,统计符合条件的山峰数量。
示例测试
输入:
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。
综合分析
-
时间复杂度:
- 预处理:两次遍历数组,时间复杂度 O(n)。
- 识别山峰:遍历数组一次,时间复杂度 O(n)。
- 总复杂度:O(n),高效处理大规模数据。
-
空间复杂度:
- 存储预处理数组和山峰位置:O(n)。
-
优势:
- 预处理优化:避免重复计算路径消耗。
- 贪心策略:选择最优路径,确保最小体力消耗。
-
适用场景:
- 处理一维数组中的山峰覆盖问题,尤其适合数据量大的场景。
更多内容:
https://www.kdocs.cn/l/cvk0eoGYucWA
本文发表于【纪元A梦】,关注我,获取更多实用教程/资源!
相关文章:
华为OD机试真题——攀登者2(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
2025 A卷 200分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C、C语言、GO六种语言的最佳实现方式! 华为OD机试真题《攀登者2》: 目录 题目名称:攀登者2…...
Windows卸载重装Docker
卸载 删除C:\Program Files\Docker ,如果更改了路径的就找到相关位置进行删除 删除 C:\Users\<用户名>\.docker 清理注册表,不然重装会报错 Exising installation is up to date 按下WindowR唤起命令输入界面,输入regedit打开注…...
JVM 为什么需要即时编译器?
JVM之所以需要即时编译器 (JIT Compiler),是为了提高 Java 程序的执行性能,弥补纯解释器执行的不足。 我们可以从以下几个角度来分析一下这个问题: 1. 解释器的性能瓶颈: 逐条解释的开销: 解释器需要逐条读取 Java 字节码指令,并…...
双目视觉中矩阵等参数说明及矫正
以下是标定文件中各个参数的详细解释: 1. 图像尺寸 (imageSize) 参数值: [1280, 1024]含义: 相机的图像分辨率,宽度为1280像素,高度为1024像素。 2. 相机内参矩阵 (leftCameraMatrix / rightCameraMatrix) 结构: yaml data: [fx, 0, cx, 0,…...
Android Compose 框架的列表与集合模块之滑动删除与拖拽深入分析(四十八)
Android Compose 框架的列表与集合模块之滑动删除与拖拽深入分析 一、引言 本人掘金号,欢迎点击关注:https://juejin.cn/user/4406498335701950 1.1 Android Compose 简介 在 Android 开发领域,界面的交互性和用户体验至关重要。传统的 A…...
一、LLM 大语言模型初窥:起源、概念与核心原理
一、初识大模型 1.1 人工智能演进与大模型兴起:从A11.0到A12.0的变迁 AI 1.0时代(2012-2022年) 感知智能的突破:以卷积神经网络(CNN)为核心,AI在图像识别、语音处理等感知任务中超越人类水平。例如&#…...
PyTorch核心函数详解:gather与where的实战指南
PyTorch中的torch.gather和torch.where是处理张量数据的关键工具,前者实现基于索引的灵活数据提取,后者完成条件筛选与动态生成。本文通过典型应用场景和代码演示,深入解析两者的工作原理及使用技巧,帮助开发者提升数据处理的灵活…...
《Operating System Concepts》阅读笔记:p636-p666
《Operating System Concepts》学习第 58 天,p636-p666 总结,总计 31 页。 一、技术总结 1.system and network threats (1)attack network traffic (2)denial of service (3)port scanning 2.symmetric/asymmetric encryption algorithm (1)symm…...
Go:接口
接口既约定 Go 语言中接口是抽象类型 ,与具体类型不同 ,不暴露数据布局、内部结构及基本操作 ,仅提供一些方法 ,拿到接口类型的值 ,只能知道它能做什么 ,即提供了哪些方法 。 func Fprintf(w io.Writer, …...
ESP32+Arduino入门(三):连接WIFI获取当前时间
ESP32内置了WIFI模块连接WIFI非常简单方便。 代码如下: #include <WiFi.h>const char* ssid "WIFI名称"; const char* password "WIFI密码";void setup() {Serial.begin(115200);WiFi.begin(ssid,password);while(WiFi.status() ! WL…...
FastAPI用户认证系统开发指南:从零构建安全API
前言 在现代Web应用开发中,用户认证系统是必不可少的功能。本文将带你使用FastAPI框架构建一个完整的用户认证系统,包含注册、登录、信息更新和删除等功能。我们将采用JWT(JSON Web Token)进行身份验证,并使用SQLite作…...
CSS高度坍塌?如何解决?
一、什么是高度坍塌? 高度坍塌(Collapsing Margins)是指当父元素没有设置边框(border)、内边距(padding)、内容(content)或清除浮动时,其子元素的 margin 会…...
【数据结构】之散列
一、定义与基本术语 (一)、定义 散列(Hash)是一种将键(key)通过散列函数映射到一个固定大小的数组中的技术,因为键值对的映射关系,散列表可以实现快速的插入、删除和查找操作。在这…...
空地机器人在复杂动态环境下,如何高效自主导航?
随着空陆两栖机器人(AGR)在应急救援和城市巡检等领域的应用范围不断扩大,其在复杂动态环境中实现自主导航的挑战也日益凸显。对此香港大学王俊铭基于阿木实验室P600无人机平台自主搭建了一整套空地两栖机器人,使用Prometheus开源框架完成算法的仿真验证与…...
python小记(十二):Python 中 Lambda函数详解
Python 中 Lambda函数详解 Lambda函数详解:从入门到实战一、什么是Lambda函数?二、Lambda的核心语法与特点1. 基础语法2. 与普通函数对比 三、Lambda的六大应用场景(附代码示例)1. 基本数学运算2. 列表排序与自定义规则3. 数据映射…...
第二十一讲 XGBoost 回归建模 + SHAP 可解释性分析(利用R语言内置数据集)
下面我将使用 R 语言内置的 mtcars 数据集,模拟一个完整的 XGBoost 回归建模 SHAP 可解释性分析 实战流程。我们将以预测汽车的油耗(mpg)为目标变量,构建 XGBoost 模型,并用 SHAP 来解释模型输出。 🚗 示例…...
数据分析实战案例:使用 Pandas 和 Matplotlib 进行居民用水
原创 IT小本本 IT小本本 2025年04月15日 18:31 北京 本文将使用 Matplotlib 及 Seaborn 进行数据可视化。探索如何清理数据、计算月度用水量并生成有价值的统计图表,以便更好地理解居民的用水情况。 数据处理与清理 读取 Excel 文件 首先,我们使用 pan…...
Asp.NET Core WebApi 创建带鉴权机制的Api
构建一个包含 JWT(JSON Web Token)鉴权的 Web API 是一种常见的做法,用于保护 API 端点并验证用户身份。以下是一个基于 ASP.NET Core 的完整示例,展示如何实现 JWT 鉴权。 1. 创建 ASP.NET Core Web API 项目 使用 .NET CLI 或 …...
hash.
Redis 自身就是键值对结构 Redis 自身的键值对结构就是通过 哈希 的方式来组织的 哈希类型中的映射关系通常称为 field-value,用于区分 Redis 整体的键值对(key-value), 注意这里的 value 是指 field 对应的值,不是键…...
记录鸿蒙应用上架应用未配置图标的前景图和后景图标准要求尺寸1024px*1024px和标准要求尺寸1024px*1024px
审核报错【①应用未配置图标的前景图和后景图,标准要求尺寸1024px*1024px且需下载HUAWEI DevEco Studio 5.0.5.315或以上版本进行图标再处理、②应用在展开状态下存在页面左边距过大的问题, 应用在展开状态下存在页面右边距过大的问题, 当前页面左边距: 504 px, 当前页面右边距…...
golang-常见的语法错误
https://juejin.cn/post/6923477800041054221 看这篇文章 Golang 基础面试高频题详细解析【第一版】来啦~ 大叔说码 for-range的坑 func main() { slice : []int{0, 1, 2, 3} m : make(map[int]*int) for key, val : range slice {m[key] &val }for k, v : …...
Google最新《Prompt Engineering》白皮书全解析
近期有幸拿到了Google最新发布的《Prompt Engineering》白皮书,这是一份由Lee Boonstra主笔,Michael Sherman、Yuan Cao、Erick Armbrust、Antonio Gulli等多位专家共同贡献的权威性指南,发布于2025年2月。今天我想和大家分享这份68页的宝贵资…...
如何快速部署基于Docker 的 OBDIAG 开发环境
很多开发者对 OceanBase的 SIG社区小组很有兴趣,但如何将OceanBase的各类工具部署在开发环境,对于不少开发者而言都是比较蛮烦的事情。例如,像OBDIAG,其在WINDOWS系统上配置较繁琐,需要单独搭建C开发环境。此外&#x…...
[LeetCode 1306] 跳跃游戏3(Ⅲ)
题面: LeetCode 1306 思路: 只要能跳到其中一个0即可,和跳跃游戏1/2完全不同了,记忆化暴搜即可。 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( n ) O(n) O(n) 代码: dfs vector<…...
spring-ai-alibaba使用Agent实现智能机票助手
示例目标是使用 Spring AI Alibaba 框架开发一个智能机票助手,它可以帮助消费者完成机票预定、问题解答、机票改签、取消等动作,具体要求为: 基于 AI 大模型与用户对话,理解用户自然语言表达的需求支持多轮连续对话,能…...
STM32平衡车开发实战教程:从零基础到项目精通
STM32平衡车开发实战教程:从零基础到项目精通 一、项目概述与基本原理 1.1 平衡车工作原理 平衡车是一种基于倒立摆原理的两轮自平衡小车,其核心控制原理类似于人类保持平衡的过程。当人站立不稳时,会通过腿部肌肉的快速调整来维持平衡。平…...
使用DeepSeek AI高效降低论文重复率
一、论文查重原理与DeepSeek降重机制 1.1 主流查重系统工作原理 文本比对算法:连续字符匹配(通常13-15字符)语义识别技术:检测同义替换和结构调整参考文献识别:区分合理引用与不当抄袭跨语言检测:中英文互译内容识别1.2 DeepSeek降重核心技术 深度语义理解:分析句子核心…...
linux多线(进)程编程——(7)消息队列
前言 现在修真界大家的沟通手段已经越来越丰富了,有了匿名管道,命名管道,共享内存等多种方式。但是随着深入使用人们逐渐发现了这些传音术的局限性。 匿名管道:只能在有血缘关系的修真者(进程)间使用&…...
WinForm真入门(14)——ListView控件详解
一、ListView 控件核心概念与功能 ListView 是 WinForm 中用于展示结构化数据的多功能列表控件,支持多列、多视图模式及复杂交互,常用于文件资源管理器、数据报表等场景。 核心特点: 支持 5种视图模式:Details&…...
Python + Playwright:规避常见的UI自动化测试反模式
Python + Playwright:规避常见的UI自动化测试反模式 前言反模式一:整体式页面对象(POM)反模式二:具有逻辑的页面对象 - POM 的“越界”行为反模式三:基于 UI 的测试设置 - 缓慢且脆弱的“舞台搭建”反模式四:功能测试过载 - “试图覆盖一切”的测试反模式之间的关联与核…...
