leetcode
leetcode 651 ~ 700
破解保险箱

破解保险箱

难度:

标签:

题目描述

代码结果

运行时间: 30 ms, 内存: 16.5 MB


/*
题目思路:
利用 De Bruijn 序列来生成所有可能的 n 位组合的最短序列。使用 Java Stream API 实现。
*/
import java.util.*;
import java.util.stream.Collectors;

public class SafeCrackerStream {
    public String crackSafe(int n, int k) {
        String start = String.join("", Collections.nCopies(n - 1, "0"));
        Set<String> visited = new HashSet<>();
        StringBuilder sb = new StringBuilder();
        visited.add(start);
        dfs(start, visited, sb, n, k);
        sb.append(start);
        return sb.toString();
    }

    private void dfs(String current, Set<String> visited, StringBuilder sb, int n, int k) {
        List<Integer> range = IntStream.range(0, k).boxed().collect(Collectors.toList());
        range.forEach(i -> {
            String next = current + i;
            if (visited.add(next)) {
                dfs(next.substring(1), visited, sb, n, k);
                sb.append(i);
            }
        });
    }

    public static void main(String[] args) {
        SafeCrackerStream sc = new SafeCrackerStream();
        System.out.println(sc.crackSafe(2, 2)); // 输出: 01100
    }
}

解释

方法:

这道题目可以使用Hierholzer算法来找到Euler路径,即一条通过图中每条边恰好一次的路径。图中的节点表示密码的前n-1位,而边则表示可能的n位密码。算法的核心是构建一个有向图,图的节点表示长度为n-1的序列,每个节点会有k条出边,这些出边对应在该序列后添加一个数字形成的n位序列。解题过程首先构建图的邻接表,然后使用深度优先搜索遍历图来寻找Euler回路,最后将这个回路转换成对应的密码序列。

时间复杂度:

O(k^n)

空间复杂度:

O(k^n)

代码细节讲解

🦆
在解题过程中,你是如何确定使用Hierholzer算法来寻找Euler路径的?
Hierholzer算法是用于寻找Euler路径的经典算法,它特别适用于需要遍历图中每条边恰好一次的问题。在破解保险箱的场景中,我们需要找到一个密码序列,该序列通过所有可能的n位密码恰好一次,这可以被抽象为在一个有向图中找到一个Euler回路。因此,考虑到题目需求和Hierholzer算法的适用性,我决定采用此算法来解决问题。
🦆
Hierholzer算法适用于哪些类型的图,即什么条件下图中存在欧拉回路或路径?
Hierholzer算法适用于有向图和无向图,但它要求图中至少存在一个欧拉路径或欧拉回路。对于无向图,欧拉回路存在的条件是所有顶点的度数都是偶数;欧拉路径存在的条件是恰有两个顶点的度数是奇数,其他顶点的度数都是偶数。对于有向图,欧拉回路存在的条件是每个顶点的入度和出度相等;欧拉路径存在的条件是恰有一个顶点的出度比入度大1,恰有一个顶点的入度比出度大1,其他顶点的入度和出度相等。
🦆
在算法中,你如何构建图的节点和边?特别是如何从节点表示长度为n-1的序列到节点有k条边的过程是如何实现的?
在这个算法中,图的节点代表长度为n-1的序列。假设使用数字0到k-1,那么有k^(n-1)种可能的序列,这些序列作为图的节点。为了构建边,对于每个节点(即每个序列),我们通过在序列末尾添加一个从0到k-1的数字来生成新的n位序列。这样,从每个节点出发都会有k条边,对应于添加不同数字得到的序列。我们通过计算来确定每个新序列对应的节点,确保边的正确连接。
🦆
在深度优先搜索(DFS)过程中,如何确保每条边只被访问一次,从而满足Euler路径的要求?
在使用DFS进行欧拉回路的搜索过程中,我们维护一个栈来记录访问的路径,并且对每个节点维护一个邻接表来记录其可达的节点。当访问一个节点时,我们将其从当前节点的邻接表中移除,这样每条边只会被访问一次。一旦一个节点没有更多可访问的边,我们就将其加入到最终的路径中。这种方法确保了每条边在整个过程中仅被访问一次,符合欧拉路径的要求。

相关问题