赞
踩
橱窗里有一排宝石,不同的宝石对应不同的价格,宝石的价格标记为gems[i],0<=i<n
,n = gems.length
。宝石可同时出售0
个或多个,如果同时出售多个,则要求出售的宝石编号连续;
例如客户最大购买宝石个数为m
,购买的宝石编号必须为gems[i],gems[i+1]...gems[i+m-1](0<=i<n,m<=n)
。假设你当前拥有总面值为value
的钱,请问最多能购买到多少个宝石。如无法购买宝石,则返回0
。
第一行输入n
,参数类型为 int
,取值范围:[0,10^6]
,表示橱窗中宝石的总数量。
之后n
行分别表示从第0
个到第n-1
个宝石的价格,即gems[0]
到gems[n-1]
的价格,类型为int
,取值范围:(0,1000]
。
之后一行输入v
,类型为int
,取值范围:[0,10^9]
表示你拥有的钱。
输出int
类型的返回值,表示最大可购买的宝石数量。
7
8
4
6
3
1
6
7
10
3
gems = [8,4,6,3,1,6,7], value = 10` 最多购买的宝石为`gems[2]`至`gems[4]`或者`gems[3]`至`gems[5]
0
1
0
gems = []`,`value = 1` 因为没有宝石,所以返回`0
9
6
1
3
1
8
9
3
2
4
15
4
gems = [6, 1, 3, 1, 8, 9, 3, 2, 4]`,`value = 15` 最多购买的宝石为`gems[0]`至`gems[3]
9
1
1
1
1
1
1
1
1
1
10
9
gems = [1, 1, 1, 1, 1, 1, 1, 1, 1], value = 10
最多购买的宝石为gems[0]
至gems[8]
,即全部购买
由于购买的宝石的下标必须连续,所以题目本质上是要求找到最长的和小于value
的连续子数组。由于所有元素均为正整数,所以考虑滑窗而非前缀和求和。直接考虑滑窗三问三答即可。
Q1:对于每一个右指针right
所指的元素num
,做什么操作?
Q2:什么时候要令左指针left
右移?left
对应的元素做什么操作?while
中的循环不变量是什么?
Q3:什么时候进行ans
的更新?
A1:将num
计入窗口之和win_sum
中。
A2:win_sum > max_sum
,win_sum
减去left_num
,left
右移,直到win_sum <= M
成立。
A3:win_sum <= M
时,可以更新答案,这个过程发生在将num
计入窗口之和win_sum
中之后。
# 题目:【不定滑窗】2023C-最大可购买的宝石数量 # 分值:100 # 作者:许老师-闭着眼睛学数理化 # 算法:不定滑窗 # 代码看不懂的地方,请直接在群上提问 # 输入宝石数组长度 n = int(input()) nums = list() # 循环n次,每次循环输入一个数,按顺序存入nums数组中 for _ in range(n): nums.append(int(input())) # 输入子数组的最大和 max_sum = int(input()) # 初始化窗口和 win_sum = 0 # 初始化左指针和ans left, ans = 0, 0 # 进行滑窗 for right, num in enumerate(nums): # A1 win_sum += num # A3 if win_sum <= max_sum: ans = max(ans, right-left+1) # A2 while win_sum > max_sum: win_sum -= nums[left] left += 1 print(ans)
import java.util.*; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int[] nums = new int[n]; for (int i = 0; i < n; i++) { nums[i] = scanner.nextInt(); } int maxSum = scanner.nextInt(); int windowSum = 0; int left = 0; int ans = 0; for (int right = 0; right < n; right++) { windowSum += nums[right]; if (windowSum <= maxSum) { ans = Math.max(ans, right - left + 1); } while (windowSum > maxSum) { windowSum -= nums[left]; left++; } } System.out.println(ans); } }
#include <iostream> #include <vector> int main() { int n; std::cin >> n; std::vector<int> nums(n); for (int i = 0; i < n; i++) { std::cin >> nums[i]; } int maxSum; std::cin >> maxSum; int windowSum = 0; int left = 0; int ans = 0; for (int right = 0; right < n; right++) { windowSum += nums[right]; if (windowSum <= maxSum) { ans = std::max(ans, right - left + 1); } while (windowSum > maxSum) { windowSum -= nums[left]; left++; } } std::cout << ans << std::endl; return 0; }
时间复杂度:O(N)
。仅需一次遍历数组nums
。
空间复杂度:O(1)
。仅需若干常数变量。
华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!
课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!
60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁
可上全网独家的欧弟OJ系统练习华子OD、大厂真题
可查看链接 大厂真题汇总 & OD真题汇总(持续更新)
绿色聊天软件戳 od1336
了解更多
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。