Leetcode力扣秋招刷题路-0753

该文介绍了一个关于密码破解的算法问题,其中密码是一个n位数,由[0,k-1]范围内的数字组成。保险箱的验证机制是基于最后n位输入,需要找出确保能打开保险箱的最短密码序列。解法涉及欧拉回路的概念,通过构建图并进行深度优先搜索,找到包含所有可能排列组合的字符串。给出的代码示例展示了如何实现这一过程。
摘要由CSDN通过智能技术生成

从0开始的秋招刷题路,记录下所刷每道题的题解,帮助自己回顾总结

753. 破解保险箱

有一个需要密码才能打开的保险箱。密码是 n 位数, 密码的每一位都是范围 [0, k - 1] 中的一个数字。

保险箱有一种特殊的密码校验方法,你可以随意输入密码序列,保险箱会自动记住 最后 n 位输入 ,如果匹配,则能够打开保险箱。

例如,正确的密码是 “345” ,并且你输入的是 “012345” :
输入 0 之后,最后 3 位输入是 “0” ,不正确。
输入 1 之后,最后 3 位输入是 “01” ,不正确。
输入 2 之后,最后 3 位输入是 “012” ,不正确。
输入 3 之后,最后 3 位输入是 “123” ,不正确。
输入 4 之后,最后 3 位输入是 “234” ,不正确。
输入 5 之后,最后 3 位输入是 “345” ,正确,打开保险箱。
在只知道密码位数 n 和范围边界 k 的前提下,请你找出并返回确保在输入的 某个时刻 能够打开保险箱的任一 最短 密码序列 。

示例 1:
输入:n = 1, k = 2
输出:“10”
解释:密码只有 1 位,所以输入每一位就可以。“01” 也能够确保打开保险箱。

示例 2:
输入:n = 2, k = 2
输出:“01100”
解释:对于每种可能的密码:

  • “00” 从第 4 位开始输入。
  • “01” 从第 1 位开始输入。
  • “10” 从第 3 位开始输入。
  • “11” 从第 2 位开始输入。
    因此 “01100” 可以确保打开保险箱。“01100”、“10011” 和 “11001” 也可以确保打开保险箱。

提示:
1 <= n <= 4
1 <= k <= 10
1 <= k n k^n kn <= 4096

解法一: 欧拉回路
前置知识: 欧拉回路:通过图中所有边一次且仅一次行遍所有顶点的回路称为欧拉回路

首先题目要求能打开保险箱的最短字符串,即将n位所有可能的排列组合都包含进去,例如00110,k = 2, n = 2,那么包含的可能位00,01,11,10将n位k进制所有的可能都包含进去因此一定能够成果试出密码。那么题目便转化为求它的包含所有排列组合的字符串。

由于每次只取最后一个字符来进行移动,例如n=3,k=2时,那么对于000,可以转化为000,001, 对于011,可以转化为110,111。根据观察,我们可以将每个状态抽象为1个点,即对于n位密码,我们将n−1的可能组合看作一个点,那么对于n=3,k=2来说包含点={00,01,10,11}

时间复杂度: O ( k n ) O(k^n) O(kn),对于每个结点都有k条边,一共有 k n − 1 k^{n-1} kn1个结点。
空间复杂度: O ( k n ) O(k^n) O(kn),为边数

class Solution {
    StringBuilder sb = new StringBuilder();
    int n, k, mod;
    Set<Integer> vis = new HashSet<>(); //判断每条边是否访问过
    public String crackSafe(int N, int K) {
        n = N; k = K; mod = (int)Math.pow(10, n - 1); 
        dfs(0); //从0点出发
        sb.append("0".repeat(n - 1));
        return sb.toString();
    }
    void dfs(int u) {
        for (int i = 0; i < k; i++) { //对于每个点循环k条边即可
            int v = u * 10 + i; //即边的编号
            if (vis.contains(v)) continue; 
            vis.add(v);    //标记该边已经访问 
            dfs(v % mod); //去掉第一位为结点编号 
            sb.append(i); //添加最后一个数字
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fffffffyy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值