华为OD2023(C&D卷)机试题库全覆盖,刷题指南点这里
攀登者2
知识点数组
时间限制:1s 空间限制:32MB 限定语言:不限
题目描述:
攀登者喜欢寻找各种地图,并且尝试攀登到最高的山峰。 地图表示为一维数组,数组的索引代表水平位置,数组的高度代表相对海拔高度。其中数组元素0代表地面。 例如[0,1,4,3,1,0,0,1,2,3,1,2,1,0], 代表如下图所示的地图,地图中有两个山脉位置分别为 1,2,3,4,5和8,9,10,11,12,13,最高峰高度分别为4,3。最高峰位置分别为3,10。 一个山脉可能有多座山峰(高度大于两边,或者在地图边界)。
4 +---+ | | | | 3 3 | | | +---+ ----- | | | | 2 | | 2 | | 2 | | | | +---+ | ----+ | +---+ | | | | | | 1 | | 1 1 | | 1 | | 1 | | | | | | +---+ +---+ +---+ +---+ +---+ | | | | 0 | | 0 0 | | 0 | | | | +---+ +-------+ +---+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 142. 登山时会消耗登山者的体力(整数),上山时,消耗相邻高度差两倍的体力,下坡时消耗相邻高度差一倍的体力,平地不消耗体力,登山者体力消耗到零时会有生命危险。 例如,上图所示的山峰,从索引0,走到索引1,高度差为1,需要消耗2X1 = 2 的体力,从索引2高度2走到高度4索引3需要消耗2X2 = 4 的体力。如果是从索引3走到索引4则消耗1X1的体力。
3. 登山者体力上限为999。
4. 登山时的起点和终点可以是地图中任何高度为0的地面例如上图中的0,6,7,14 都可以作为登山的起点和终点
攀登者想要评估一张地图内有多少座山峰可以进行攀登,且可以安全返回到地面,且无生命危险。
例如上图中的数组,有3个不同的山峰,登上位置在3的山可以从位置0或者位置6开始,从位置0登到山顶需要消耗体力1X2+1X2+2X2 = 8, 从山顶返回到地面0需要消耗体力 2X1 + 1X1 + 1X1 = 4 的体力,按照登山路线0->3->0需要消耗体力 12。攀登者至少需要12以上的体力(大于12)才能安全返回。
示例1
输入:
[0,1,4,3,1,0,0,1,2,3,1,2,1,0],13输出:
3说明:
登山者只能够登上位置10和12的山峰,7->10->7, 14->12>14
示例2
输入:
[1,4,3],999输出:
0说明:
没有合适的起点和终点
代码(JAVA):
import java.util.HashSet; import java.util.Set; public class Main{ public static void main(String[] args) { int[] hillMap = new int[]{0,1,4,3,1,0,0,1,2,3,1,2,1,0}; System.out.println(count_climbable( hillMap, 13)); } public static int count_climbable(int[] hill_map, int strength) { if (hill_map.length <= 1) { return 0; } int result = 0; //峰的位置集合 Set<Integer> feng = new HashSet<>(); for (int i = 0; i < hill_map.length; i++) { if (hill_map[i] != 0) { boolean flag = false; if (i == 0 && i + 1 < hill_map.length && hill_map[i + 1] < hill_map[i]) { //第一个位置为峰 flag = true; } if (i == hill_map.length - 1 && i > 0 && hill_map[i] > hill_map[i - 1]) { //最后一个为峰 flag = true; } if (i > 0 && i < hill_map.length - 1 && hill_map[i - 1] < hill_map[i] && hill_map[i] > hill_map[i + 1]) { //中间位置为峰 flag = true; } if (flag) { feng.add(i); } } } //从左侧地面上山 int[][] left = new int[hill_map.length][2]; int i = 0; //上山的高度 int v1 = -1; //下山的高度 int v2 = -1; while (i < hill_map.length) { if (hill_map[i] == 0) { v1 = 0; v2 = 0; } else if (v1 != -1) { if (hill_map[i] > hill_map[i - 1]) { v1 += hill_map[i] - hill_map[i - 1]; } else { v2 += hill_map[i - 1] - hill_map[i]; } } left[i][0] = v1; left[i][1] = v2; i++; } //从右侧地面上山 int[][] right = new int[hill_map.length][2]; i = hill_map.length - 1; //上山的高度 v1 = -1; //下山的高度 v2 = -1; while (i >= 0) { if (hill_map[i] == 0) { v1 = 0; v2 = 0; } else if (v1 != -1) { if (hill_map[i] > hill_map[i + 1]) { v1 += hill_map[i] - hill_map[i + 1]; } else { v2 += hill_map[i + 1] - hill_map[i]; } } right[i][0] = v1; right[i][1] = v2; i--; } for (int x : feng) { boolean flag = false; int cost1 = -1; int cost2 = -1; int cost3 = -1; int cost4 = -1; if (left[x][0] != -1) { //从左侧上山下山 //上山的体力 cost1 = left[x][0] * 2 + left[x][1]; //下山的体力 cost3 = left[x][1] * 2 + left[x][0]; if (cost1 + cost3 < strength) { //体力满足登上高峰 flag = true; } } if (right[x][0] != -1) { //从右侧上山下山 //上山的体力 cost2 = right[x][0] * 2 + right[x][1]; //下山的体力 cost4 = right[x][1] * 2 + right[x][0]; if (cost2 + cost4 < strength) { flag = true; } } if (cost1 != -1 && cost2 != -1) { if (Math.min(cost1, cost2) + Math.min(cost4, cost3) < strength) { //最小上山体力 + 最小下山体力 flag = true; } } if (flag) { result ++; } } return result; } }
代码(JS):
let hillMap = [0, 1, 4, 3, 1, 0, 0, 1, 2, 3, 1, 2, 1, 0]; function count_climbable(hill_map, strength) { if (hill_map.length <= 1) { return 0; } let result = 0; //峰的位置集合 let feng = new Set(); for (let i = 0; i < hill_map.length; i++) { if (hill_map[i] !== 0) { let flag = false; if (i === 0 && i + 1 < hill_map.length && hill_map[i + 1] < hill_map[i]) { //第一个位置为峰 flag = true; } if (i === hill_map.length - 1 && i > 0 && hill_map[i] > hill_map[i - 1]) { //最后一个为峰 flag = true; } if (i > 0 && i < hill_map.length - 1 && hill_map[i - 1] < hill_map[i] && hill_map[i] > hill_map[i + 1]) { //中间位置为峰 flag = true; } if (flag) { feng.add(i); } } } //从左侧地面上山 let left = new Array(hill_map.length).fill(0).map(() => new Array(2).fill(0)); let i = 0; //上山的高度 let v1 = -1; //下山的高度 let v2 = -1; while (i < hill_map.length) { if (hill_map[i] === 0) { v1 = 0; v2 = 0; } else if (v1 !== -1) { if (hill_map[i] > hill_map[i - 1]) { v1 += hill_map[i] - hill_map[i - 1]; } else { v2 += hill_map[i - 1] - hill_map[i]; } } left[i][0] = v1; left[i][1] = v2; i++; } //从右侧地面上山 let right = new Array(hill_map.length).fill(0).map(() => new Array(2).fill(0)); i = hill_map.length - 1; //上山的高度 v1 = -1; //下山的高度 v2 = -1; while (i >= 0) { if (hill_map[i] === 0) { v1 = 0; v2 = 0; } else if (v1 !== -1) { if (hill_map[i] > hill_map[i + 1]) { v1 += hill_map[i] - hill_map[i + 1]; } else { v2 += hill_map[i + 1] - hill_map[i]; } } right[i][0] = v1; right[i][1] = v2; i--; } for (let x of feng) { let flag = false; let cost1 = -1; let cost2 = -1; let cost3 = -1; let cost4 = -1; if (left[x][0] !== -1) { //从左侧上山下山 //上山的体力 cost1 = left[x][0] * 2 + left[x][1]; //下山的体力 cost3 = left[x][1] * 2 + left[x][0]; if (cost1 + cost3 < strength) { //体力满足登上高峰 flag = true; } } if (right[x][0] !== -1) { //从右侧上山下山 //上山的体力 cost2 = right[x][0] * 2 + right[x][1]; //下山的体力 cost4 = right[x][1] * 2 + right[x][0]; if (cost2 + cost4 < strength) { flag = true; } } if (cost1 !== -1 && cost2 !== -1) { if (Math.min(cost1, cost2) + Math.min(cost4, cost3) < strength) { //最小上山体力 + 最小下山体力 flag = true; } } if (flag) { result++; } } return result; } console.log(count_climbable(hillMap, 13));