目录
3376. 破解锁的最少时间 I
题目描述:
实现代码与解析:
DFS
原理思路:
3376. 破解锁的最少时间 I
题目描述:
Bob 被困在了一个地窖里,他需要破解 n
个锁才能逃出地窖,每一个锁都需要一定的 能量 才能打开。每一个锁需要的能量存放在一个数组 strength
里,其中 strength[i]
表示打开第 i
个锁需要的能量。
Bob 有一把剑,它具备以下的特征:
- 一开始剑的能量为 0 。
- 剑的能量增加因子
X
一开始的值为 1 。 - 每分钟,剑的能量都会增加当前的
X
值。 - 打开第
i
把锁,剑的能量需要到达 至少strength[i]
。 - 打开一把锁以后,剑的能量会变回 0 ,
X
的值会增加一个给定的值K
。
你的任务是打开所有 n
把锁并逃出地窖,请你求出需要的 最少 分钟数。
请你返回 Bob 打开所有 n
把锁需要的 最少 时间。
示例 1:
输入:strength = [3,4,1], K = 1
输出:4
解释:
时间 | 能量 | X | 操作 | 更新后的 X |
---|---|---|---|---|
0 | 0 | 1 | 什么也不做 | 1 |
1 | 1 | 1 | 打开第 3 把锁 | 2 |
2 | 2 | 2 | 什么也不做 | 2 |
3 | 4 | 2 | 打开第 2 把锁 | 3 |
4 | 3 | 3 | 打开第 1 把锁 | 3 |
无法用少于 4 分钟打开所有的锁,所以答案为 4 。
示例 2:
输入:strength = [2,5,4], K = 2
输出:5
解释:
时间 | 能量 | X | 操作 | 更新后的 X |
---|---|---|---|---|
0 | 0 | 1 | 什么也不做 | 1 |
1 | 1 | 1 | 什么也不做 | 1 |
2 | 2 | 1 | 打开第 1 把锁 | 3 |
3 | 3 | 3 | 什么也不做 | 3 |
4 | 6 | 3 | 打开第 2 把锁 | 5 |
5 | 5 | 5 | 打开第 3 把锁 | 7 |
无法用少于 5 分钟打开所有的锁,所以答案为 5 。
提示:
n == strength.length
1 <= n <= 8
1 <= K <= 10
1 <= strength[i] <= 106
实现代码与解析:
DFS
class Solution {
public int findMinimumTime(List<Integer> strength, int k) {
dfs(0, 0, strength.toArray(new Integer[strength.size()]), k);
return res;
}
int res = 0x3f3f3f3f;
private void dfs(int cnt, int cur, Integer[] strength, int k) {
if (cur >= res) {
return;
}
if (cnt == strength.length) {
res = cur;
return;
}
int x = 1 + k * cnt;
for (int i = 0; i < strength.length; i++) {
if (strength[i] == -1) continue;
int tmp = strength[i];
strength[i] = -1;
dfs(cnt + 1, cur + (tmp - 1) / x + 1, strength, k);
strength[i] = tmp;
}
}
}
原理思路:
dfs全排列遍历。
cnt
:已处理锁的序号(从 0 起),据此知晓当前开锁阶段,也能算能量增加因子。cur
:当前累计时间。strength
:存各锁所需能量值的数组,递归中通过标记元素,设为 -1表示锁是否已处理。k
:与剑能量增加因子变化规则相关,开锁后按其增加,用于准确算剑能量增长情况。
递归边界条件及剪枝操作:
if (cur >= res)
是剪枝判断,若当前累计时间大于等于已找到的最少时间,当前开锁策略不优,直接返回,避免多余搜索分支。if (cnt == strength.length)
是终止条件,处理完所有锁,若cur
小于res
(即更优),将cur
更新给res
后返回。
核心递归逻辑及操作:
- 先算
x = 1 + k * cnt
,x
为当前剑能量增加因子,初始值 1(cnt = 0
时),开锁后按k
增加,用于算积攒能量开下锁的时间。 for
循环遍历strength
数组:if (strength[i] == -1)
跳过已标记 -1 的元素,意味着已处理过。int tmp = strength[i];
保存当前锁能量值,方便后续操作与恢复。strength[i] = -1;
标记当前锁已处理。dfs(cnt + 1, cur + (tmp - 1) / x + 1, strength, k);
核心递归,处理下锁,更新cur
,(tmp - 1) / x + 1
算开当前锁额外花费等待时间,向上取整,继续下一层递归。strength[i] = tmp;
递归结束后恢复元素值,便于回溯尝试其他开锁顺序。