跳格子3 - 华为OD统一考试(C卷)

OD统一考试(C卷)

分值: 200分

题解: Java / Python / C++

alt

题目描述

小明和朋友们一起玩跳格子游戏,

每个格子上有特定的分数 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

题解

这道题是一个典型的动态规划问题。解题思路如下:

  1. 创建一个数组 dp,其中 dp[i] 表示跳到 score[i-1] 时能得到的最大得分。
  2. 使用大顶堆(或者优先队列)来维护前 k 个最大的 dp 值,以便在每一步更新 dp[i] 时能够找到前 k 个最大值。
  3. 从左到右遍历格子,更新 dp[i+1] 的值。具体更新方式为当前格子的分数加上前 k 个最大的 dp 值。
  4. 输出 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;
}

相关练习题

alt

🙏整理题解不易, 如果有帮助到您,请给点个赞 ‍❤️‍ 和收藏 ⭐,让更多的人看到。🙏🙏🙏

#面经##春招##秋招##校招##华为#
全部评论
int n = in.nextInt(); int[] arr = new int[n]; for (int i = 0; i < n; i ) { arr[i] = in.nextInt(); } if (arr.length == 1){ System.out.println(arr[0]); continue; } int k = in.nextInt(); int[] dp = new int[arr.length]; Deque<Integer> deque = new LinkedList<>(); for (int i = 0; i < arr.length; i ) { if (!deque.isEmpty() &amp;&amp; i - deque.peekFirst() > k) { deque.pollFirst(); } dp[i] = (deque.isEmpty() ? 0 : dp[deque.peekFirst()]) arr[i]; while (!deque.isEmpty() &amp;&amp; dp[i] >= dp[deque.peekLast()]) { deque.pollLast(); } deque.offerLast(i); } System.out.println(dp[dp.length-1]);
点赞 回复 分享
发布于 2024-05-06 17:51 北京
动态规划 大堆也只能通过95%的测试用例,剩余的5%不知道要怎么才能通过。
点赞 回复 分享
发布于 2024-05-06 13:43 北京

相关推荐

如题,他是要劝退我了吗
椛鸣:根据你的时间 来给你安排任务 如果你时间长 可能会参与到一些长期的项目 时间短 那就只能做点零工
点赞 评论 收藏
分享
LemontreeN:有的兄弟有的我今天一天面了五场,4个二面一个hr面
投递字节跳动等公司7个岗位
点赞 评论 收藏
分享
评论
7
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务