带奖励工位的玩具包装最优解算法实现与调试求助
带奖励工位的玩具包装最优解算法实现与调试求助
问题背景与需求
我们需要完成一批玩具的包装任务,每个玩具的包装需要消耗不同的能量。同时有多个包装工位可用,每个工位都有特殊奖励规则:如果在该工位付费包装指定数量的玩具,就能解锁2个免费包装名额,但免费包装的玩具,其能量消耗必须不超过该工位已付费包装的玩具中,能量消耗最小的那个。我们的目标是找到最优策略,用最少的总能量完成所有玩具的包装。
示例场景:
玩具能量列表:[50, 50, 30, 50, 20]
工位规则:
- 工位1:付费包装2个玩具 → 解锁2个免费包装名额
- 工位2:付费包装3个玩具 → 解锁2个免费包装名额
最优方案:用工位1付费包装2个50能量的玩具,解锁免费名额后,用免费包装覆盖30和50能量的玩具(50等于已付费玩具的最小能量,符合规则),最后20能量的玩具随便在哪包装。总消耗能量为50+50+20=120
约束条件
- 工位规则数量
n:1 ≤ n ≤ 10^5 - 单个工位要求的付费包装数
stationRules[i]:1 ≤ stationRules[i] ≤ 10^5 - 玩具数量
m:1 ≤ m ≤ 10^5 - 单个玩具的包装能量
toyWrapEffort[i]:1 ≤ toyWrapEffort[i] ≤ 10^4
我的思路与实现
我采用了贪心算法来解决这个问题,核心思路如下:
- 把玩具按包装能量从高到低排序:高能量玩具的包装成本最高,优先付费包装它们,这样解锁的免费名额可以覆盖尽可能多的高/等能量玩具,最大化节省的能量。
- 把工位规则按要求的付费包装数从小到大排序:优先使用解锁免费名额门槛更低的工位,能更早拿到免费名额,覆盖更多玩具。
- 遍历排序后的玩具,优先使用免费名额抵消包装,没有免费名额时就付费包装,同时计数,达到工位要求的付费数量就解锁2个免费名额。
实现代码
import java.util.*; class Main { public static int wrapToysSmartly(List<Integer> stationRules, List<Integer> toyWrapEffort) { // 玩具按包装能量降序排序 Collections.sort(toyWrapEffort, Collections.reverseOrder()); // 工位按要求的付费数量升序排序 Collections.sort(stationRules); int toyCount = toyWrapEffort.size(), stationCount = stationRules.size(); long totalEnergy = 0; int freeSlots = 0; int paidToyCount = 0; int currentStationIdx = 0; for (int i = 0; i < toyCount; i++) { int currentEffort = toyWrapEffort.get(i); if (freeSlots > 0) { // 优先使用免费包装名额 freeSlots--; } else { // 付费包装,累加能量消耗 totalEnergy += currentEffort; paidToyCount++; // 检查是否满足当前工位的免费名额解锁条件 if (currentStationIdx < stationCount && paidToyCount >= stationRules.get(currentStationIdx)) { // 解锁2个免费名额 freeSlots += 2; // 重置当前工位的付费计数,切换到下一个工位 paidToyCount -= stationRules.get(currentStationIdx); currentStationIdx++; } } } return (int) totalEnergy; } public static void main(String... args) { // 测试用例1:示例场景,预期输出120 System.out.println(wrapToysSmartly(Arrays.asList(2, 3), Arrays.asList(50, 50, 30, 50, 20))); // 测试用例2:预期输出143 System.out.println(wrapToysSmartly(Arrays.asList(5, 5, 2), Arrays.asList(48, 75, 20, 46, 33))); // 测试用例3:预期输出357 System.out.println(wrapToysSmartly(Arrays.asList(4, 4, 7), Arrays.asList(64, 38, 95, 34, 33, 96, 10, 59))); } }
遇到的问题
我自己编写的三个测试用例都能正常通过,但在Hackerrank平台提交后,15个测试用例中有4个隐藏用例失败了。我猜测可能是我的贪心逻辑忽略了某个约束细节,比如:
- 免费名额是和特定工位绑定的,不能跨工位混用?
- 免费包装的玩具必须严格小于已付费玩具的最小能量,而不是小于等于?
- 工位的使用顺序或者计数逻辑有问题?
另外,我也想确认当前的时间复杂度(O(n log n + m log m + m))是否是最优的,有没有进一步优化的空间。
请求帮助
- 我的代码逻辑存在什么漏洞?为什么会导致隐藏用例失败?
- 针对这个问题,正确的贪心策略应该如何调整才能满足所有约束条件?
- 这个问题的最优时间复杂度是多少?有没有可以优化的细节?
内容来源于stack exchange
相关产品推荐
相关产品推荐

