华为OD-2024年E卷-跳格子三[200分] -- python

问题描述:

小明和朋友们一起玩跳格子游戏,每个格子上有特定的分数, score[] = [1 -1 -6 7 -17 7],从起点score[0]开始,每次最大跳的步长为k,请你返回小明跳到终点score[n-1]时,能得到的最大得分。
注:
·格子的总长度和步长的区间在[1,100000];
·每个格子的分数在[-10000,10000]区间中;

输入描述:

6//第一行输入总的格子数量
1 -1 -6 7 -17 7//第二行输入每个格子的分数score[]
2//第三行输入最大跳的步长k

输出描述

14
//输出最大得分数,小明从起点score[0]开始跳,第一次跳到score[1],
第二次跳到score[3],第三次跳到score[5],因此得到的最大的得分是score[0]+score[1]+score[3]+score[5]=14
6
1 -1 -6 7 -17 7
2

解题思路:

动态规划:使用dp数组来存储到达每一步能得到的最大分数

状态转移方程:dp[i] = max(dp[i],arr[i]+dp[i-j]),i为遍历原数组,j为步长

即:寻找到达当前的[1,k]步中最大的值,如下:

    # for j in range(1,k+1):
    #     if i-j >= 0:
    #         dp[i] = max(dp[i],arr[i]+dp[i-j])

如何优化呢?

再次使用一个双端队列deque:维护步长两端之间的最大值,这里以左端最大值为例

  1. deque存储元素为原列表索引
  2. 左端:窗口大小就是步长k,i-k为当前走k步的最小索引,移除元素
  3. 右端:如果当前dp[i]大于dp[deque[0]],移除右端元素。保证当前deque[0]为最大值索引

以输入示例为例:

列表\索引遍历(i-k) 0 1 2 3 4 5
arr 1 -1 -6 7 -17 7
deque [0] [0,1] [0,1,2] [3] [3,4] [5]
初始化0 加入1 加入2

左移除0

右移除2

右移除1

加入4

右移除4

右移除3

dp 1 0 -5 7 -10 14

代码实现:

from math import inf
from collections import deque
n = int(input())
arr = list(map(int,input().split()))
k = int(input())
dp = [-inf]*n
dp[0] = arr[0]
q = deque([0])#双端队列,存储索引
for i in range(1,n):
    # for j in range(1,k+1):
    #     if i-j >= 0:
    #         dp[i] = max(dp[i],arr[i]+dp[i-j])
    
    while q and q[0] < i-k:#q[0]为左端元素,i-k为开始滑动的标准
        q.popleft()#移除左端元素
    dp[i] = arr[i] + dp[q[0]]
    while q and dp[i] >= dp[q[-1]]:#保证dp[0]最大
        q.pop()#移除右端元素
    q.append(i)
print(dp[n-1])#dp[n-1]=dp[-1];-1表示倒数第一个,即倒序

你可能感兴趣的:(华为od,python,开发语言)