LC-753.破解保险箱

题目描述

leetcode 困难题

有一个需要密码才能打开的保险箱。密码是 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:

1
2
3
4
5
6
7
8
输入:n = 2, k = 2
输出:"01100"
解释:对于每种可能的密码:
- "00" 从第 4 位开始输入。
- "01" 从第 1 位开始输入。
- "10" 从第 3 位开始输入。
- "11" 从第 2 位开始输入。
因此 "01100" 可以确保打开保险箱。"01100""10011""11001" 也可以确保打开保险箱。

提示1:

1
2
3
1 <= n <= 4
1 <= k <= 10
1 <= kn <= 4096

Hierholzer 算法

实际上是求以所有 $n - 1$ 位密码组合作为顶点所构成图的 欧拉回路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
private int numRange;
private int mod;
private StringBuilder ans = new StringBuilder();
private Set<Integer> visit = new HashSet<>();

public String crackSafe(int n, int k) {
numRange = k;
mod = (int)Math.pow(10, n - 1);
hierholzer(0); // 实际上起点是 n - 1 个 0 , 但是 * 10 后都为 0 , 所以直接取 0 也行
return ans.append("0".repeat(n - 1)).toString();
}

private void hierholzer(int p){
for(int i = 0; i < numRange; i++){
int e = p * 10 + i;
if(!visit.add(e)){
continue;
}
hierholzer(e % mod); // 用简单回路替换 i 点
ans.append(i);
}
}
}

LC-753.破解保险箱
https://wecgwm.github.io/2023/02/06/LC-753-破解保险箱/
作者
yichen
发布于
2023年2月6日
许可协议