LeetCode:3376. 破解锁的最少时间 I(DFS回溯 Java)

目录

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
001什么也不做1
111打开第 3 把锁2
222什么也不做2
342打开第 2 把锁3
433打开第 1 把锁3

无法用少于 4 分钟打开所有的锁,所以答案为 4 。

示例 2:

输入:strength = [2,5,4], K = 2

输出:5

解释:

时间能量X操作更新后的 X
001什么也不做1
111什么也不做1
221打开第 1 把锁3
333什么也不做3
463打开第 2 把锁5
555打开第 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 * cntx 为当前剑能量增加因子,初始值 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; 递归结束后恢复元素值,便于回溯尝试其他开锁顺序。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值