跳格子3 - 华为OD统一考试(C卷)-免费看题解

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

题解

动态规划:

  1. 创建一个数组 dp,其中 dp[i] 表示跳到 score[i] 时能得到的最大得分。
  2. 状态转移方程:dp[i] = max(dp[i-1],dp[i-2],...,dp[i-k]) + score[i];
  3. 但只是这样只能过40%的测试用例

大顶堆优化:

  1. 使用大顶堆来维护前 k 个dp 值,以便在每一步更新 dp[i] 时直接从堆顶取得最大值。
  2. 这样大概能过95%的测试用例

单调队列优化:

  1. 使用双向队列从尾部添加dp[i]的下标i,添加之前判断队列尾部的下标last对应的元素dp[last]是否比dp[i]小
  2. dp[last]比dp[i]小,则将dp[last]取出丢弃。因为在dp[i]前面的比dp[i]还小的值不会被后面使用到,后面要的是最大值。
  3. 这样队列里保存的下标对应的dp元素是单调递减的。较小的元素直接淘汰,无需多次排序。

动态规划+大顶堆:

public static void main(String[] args) {
	Scanner in = new Scanner(System.in);
	while (in.hasNextInt()) {
		long start = System.currentTimeMillis();
		int n = in.nextInt();
		int[] arr = new int[n];// 每个格子的分数,格子最少长度为1,格子分数可以为负数
		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();// 最大步长,即步长为1-k之间
		int[] dp = new int[arr.length];
		PriorityQueue<Integer> queue = new PriorityQueue<>(Collections.reverseOrder());
		for (int i = 0; i < arr.length; i++) {
			if (i==0){
				dp[i] = arr[0];
			}else {
				dp[i] = queue.peek() + arr[i];
			}
			queue.add(dp[i]);
			if (i-k>=0){
				queue.remove(dp[i-k]);
			}
		}
		System.out.println(dp[dp.length-1]);
	}
}

动态规划+单调队列:

public static void main(String[] args) {
	Scanner in = new Scanner(System.in);
	while (in.hasNextInt()) {
		int n = in.nextInt();
		int[] arr = new int[n];// 每个格子的分数,格子最少长度为1,格子分数可以为负数
		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();// 最大步长,即步长为1-k之间
		int[] dp = new int[arr.length];
		// 使用一个双端队列来维护单调递减的索引
		Deque<Integer> deque = new LinkedList<>();
		for (int i = 0; i < arr.length; i++) {
			// 移除队列中超出步长限制的索引
			if (!deque.isEmpty() && i - deque.peekFirst() > k) {
				deque.pollFirst();
			}
			// 更新当前位置的最大得分
			dp[i] = (deque.isEmpty() ? 0 : dp[deque.peekFirst()]) + arr[i];
			// 保持单调递减性质,比当前dp[i]还小的dp[i-x]已经没有用了,要取也是取当前dp[i]或前面更大的值
			while (!deque.isEmpty() && dp[i] >= dp[deque.peekLast()]) {
				// 队列中无用的索引移除
				deque.pollLast();
			}
			// 将当前索引加入队列
			deque.offerLast(i);
			// 对于dp数组 8 5 4 3 7 0 0,假如步长k=4,arr[4]=-1
			// i=4时队列里存的dp的索引index为 0 1 2 3,其对应的dp元素是递减的
			// 计算dp[4] = 8 + arr[4] = 7
			// 此时,dp数组中dp[1] dp[2] dp[3]都比dp[4] 小,将队列中的对应index移除
			// 最后添加当前索引i=4到队列末尾,此时队列中的index对应的dp元素还是递减的
		}
		System.out.println(dp[dp.length-1]);
	}
}

全部评论
第一种有哪些测试用例通过不了啊,我感觉都是可以的
点赞
送花
回复
分享
发布于 05-27 14:45 浙江

相关推荐

头像
04-29 11:17
C++
本人情况:本科211科班,考研二战失败,1年空窗期,本科期间没有找实习,可以说对工作这方面了解太少了,犹豫的时候看别人的面经关注了@华为HR(OD)郑经理(240308510)&nbsp;这位,她很贴心地私信我了解了情况,然后开始准备od机试。Base:成都一、机试3月27号开始准备机试,因为个人原因耽误了时间4月9号才完成机试,正常情况下一周时间准备即可。三道题分别是找朋友、火星文计算和可处理的最大任务数,运气比较好400分通过。Hr会给你发题库,我的建议是可以做**hot100里面的简单题和中等题,然后去csdn上找一下今年od机试c卷的题做做。二、性格测试4月10日完成性格测试,按hr辅导的做就能通过。三、hr资面4月11日进行资面,比较轻松,在简单的自我介绍后hr问了一些我的基本情况,问了一点简历上写的项目,问如何看待加班,然后向面试官提问。四、技术一面4月15日技术一面,先自我介绍,然后询问简历上的项目,问项目中间遇到了什么困难以及怎么解决的。然后手撕代码,先撕了**#20有效的括号,然后又出了一道#14最长公共前缀,都通过了,之后面试官会问你答题的思路。之后就是八股,c与c++的区别、c++的内存分布模型、栈和堆的区别,其他的几个问题忘了。还根据简历上课程询问了数据库,linux操作系统,不过我忘得差不多了,面试官也没有为难。最后向面试官提问。五、技术二面4月16日技术二面,二面有点折磨,上来先手撕代码#300最长递增子序列,通过了但是思路有点没解释清楚。之后就被拷打了,问了很多问题,静态变量和局部变量、深拷贝与浅拷贝、虚拟内存相关、面向对象、多态、构造函数和析构函数、类、模板、union、左值和右值、强制类型转换,数据结构常用的树,包括红黑树也问到了,数据库和算法、软件测试。面试管还会延申提问比如我提到了排序,面试官就问有哪些常见的排序方法然后问了我归并排序的思路以及时间复杂度。因为太久没复习了加上面试准备时间挺短的,大概只能回答上一半的问题,总共面试了一整个小时多几分钟才结束。六、主管面4月17日主管面,主管人很好。自我介绍后询问了基本情况,问了点项目相关的问题,然后也简单问了一些c++八股,c和c++的区别、内存泄露、多态等。然后对部门做了简单的介绍,接着就是向他提问,整体比较轻松,谈到了期望薪资。4月25日收到offer。
查看16道真题和解析
点赞 评论 收藏
转发
3 4 评论
分享
牛客网
牛客企业服务