OD统一考试(C卷)
分值: 200分
题解: Java / Python / C++
题目描述
小明和朋友们一起玩跳格子游戏,
每个格子上有特定的分数 score = [1, -1, -6, 7, -17, 7],
从起点score[0]开始,每次最大的步长为k,请你返回小明跳到终点 score[n-1] 时,能得到的最大得分。
输入描述
第一行输入总的格子数量 n
第二行输入每个格子的分数 score[i]
第三行输入最大跳的步长 k
输出描述
输出最大得分
备注
- 格子的总长度 n 和步长 k 的区间在 [1, 100000]
- 每个格子的分数 score[i] 在 [-10000, 10000] 区间中
示例1
输入:
6
1 -1 -6 7 -17 7
2
输出:
14
说明:
输出最大得分数,小明从起点score[0]开始跳,第一次跳score[1],第二次跳到score[3],第三次跳到score[5],因此得到的最大的得分是score[0] + score[1] + score[3] + score[5] = 14
题解
这道题是一个典型的动态规划问题。解题思路如下:
- 创建一个数组
dp
,其中dp[i]
表示跳到score[i-1]
时能得到的最大得分。- 使用大顶堆(或者优先队列)来维护前
k
个最大的dp
值,以便在每一步更新dp[i]
时能够找到前k
个最大值。- 从左到右遍历格子,更新
dp[i+1]
的值。具体更新方式为当前格子的分数加上前k
个最大的dp
值。- 输出
dp[n]
,即跳到终点时的最大得分。
Java
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Scanner;
/**
* @author code5bug
*/
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] score = new int[n];
for (int i = 0; i < n; i++) score[i] = scanner.nextInt();
int k = scanner.nextInt();
// dp[i] 表示跳到 score[i-1] 能得到的最大得分
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MIN_VALUE);
dp[0] = 0;
// 大顶堆实现, 堆中的元素: new int[]{跳到第i步最大得分, 下标i}
PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> Integer.compare(b[0], a[0]));
heap.offer(new int[]{dp[0], -1});
for (int i = 0; i < n; i++) {
// 移除窗口范围之外的元素
while (!heap.isEmpty() && i - heap.peek()[1] > k) heap.poll();
// heap.peek()[0] 堆顶元素即为 dp[i] 前 k 个最大的 max(dp[i-1], dp[i-2], ... , dp[i - k])
dp[i + 1] = score[i] + heap.peek()[0];
heap.offer(new int[]{dp[i + 1], i});
}
System.out.println(dp[n]);
}
}
Python
from math import inf
from heapq import heappush, heappop
n = int(input())
score = list(map(int, input().split()))
k = int(input())
# dp[i] 表示跳到 score[i-1] 能得到的最大得分
dp = [-inf] * (n + 1)
dp[0] = 0
# 大顶堆实现: 存入时将数据转负数,取用的时候再转换过来。
# 堆中的元素: (跳到第i步最大得分, 下标i)
h = []
heappush(h, (-dp[0], -1))
for i, s in enumerate(score):
while h and i - h[0][1] > k: # 移除窗口范围之外的元素
heappop(h)
# -h[0][0] 堆顶元素即为 dp[i] 前 k 个最大的 max(dp[i-1], dp[i-2], ... , dp[i - k])
dp[i+1] = s - h[0][0]
heappush(h, (-dp[i+1], i))
print(dp[-1])
C++
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int main() {
int n, k;
cin >> n;
vector<int> score(n);
for (int i = 0; i < n; i++) cin >> score[i];
cin >> k;
// dp[i] 表示跳到 score[i-1] 能得到的最大得分
vector<int> dp(n + 1, INT_MIN);
dp[0] = 0;
// 大顶堆实现, 堆中的元素: {跳到第i步最大得分, 下标i}
priority_queue<pair<int, int>> heap;
heap.push({dp[0], -1});
for (int i = 0; i < n; i++) {
// 移除窗口范围之外的元素
while (!heap.empty() && i - heap.top().second > k) {
heap.pop();
}
// heap.top().first 堆顶元素即为 dp[i] 前 k 个最大的 max(dp[i-1], dp[i-2], ... , dp[i - k])
dp[i + 1] = score[i] + heap.top().first;
heap.push({dp[i + 1], i});
}
cout << dp[n] << endl;
return 0;
}
相关练习题
题号 | 题目 | 难易 |
---|---|---|
LeetCode 45 | 45. 跳跃游戏 II | 中等 |
❤️华为OD机试面试交流群(每日真题分享): 加V时备注“华为od加群”
🙏整理题解不易, 如果有帮助到您,请给点个赞 ❤️ 和收藏 ⭐,让更多的人看到。🙏🙏🙏