所有可能的密码总数 k^n,如果把这些密码都拼起来,长度 n*k^n

如果每个密码与前一个密码共用 n-1 位,那么长度缩减为 k^n + (n-1)

上述字符串也被称为 De Bruijn sequence。

所以问题转变为,如果得到这个序列。很容易想到转化为图的问题来做,而且可以转化不同的问题。

 -> Hamilton Path

如果把所有可能的密码分别作为节点,通过共用 n-1 位转换得到的节点间添加有向边 (因此每个节点有 k 条边),如 X000 -1-> 0001 。原问题就转化为了寻找 Hamilton Path 的问题。但是判断以及寻找 Hamilton Path 是 NP-Complete 问题,因此只能暴力回溯去做。最后的答案就是 初始选择的节点+转换时添加位。

由于本题的图的对称性以及别的较好的性质,Hamilton Path 是一定存在的,而且甚至不需要回溯就能找到路径。但是由于主题思路还是回溯,回溯部分代码还是添加上使得思路更加清晰。

class Solution {
public:string res;string crackSafe(int n, int k) {int size=pow(k,n); // number of all possible passwords res.resize(n,'0');unordered_set<string> visited{res};if (dfs(string(n,'0'),size,k,visited))return res;return "";}bool dfs(string node, int size, int k, unordered_set<string> &visited){if (visited.size()==size) return true;// n-1 digits of last passwordstring suffix=node.substr(1);for (char ch='0';ch<'0'+k;++ch){string newNode=suffix+ch;if (!visited.count(newNode)){visited.insert(newNode); res.push_back(ch);if (dfs(newNode,size,k,visited)) return true;res.pop_back(); visited.erase(newNode);}}return false;}
};

-> Euler Circuit

每个密码的最后 n-1 位作为节点,通过共用这 n-1 位转换得到的节点间添加有向边,每个节点同样有 k 条边,如 000 -1-> 001 。原问题就转化为寻找 Euler Path 的问题,因为每个节点加上出去边上的那一位就是一种密码,要得到所有密码,必须访问每条边一次。要最短的字符串,就是 Euler Circuit 的问题。Eular Circuit 是可以在多项式时间内有解的。

Hierholzer's Algorithm 可以 O(V+E) 内找到 Euler Circuit,详见以下链接。由于链接里是把节点一次print出来,所以更加繁琐一点。https://www.geeksforgeeks.org/hierholzers-algorithm-directed-graph/

对于本题,我们只需要任意一个点加上所有路径上的字符即可。所有路径可以通过后序遍历轻松得到 (和上述链接做法本质一样)。其实连reverse都不用,因为是无向图。

class Solution {
public:string res;string crackSafe(int n, int k) {unordered_set<string> visited;res = "";dfs(string(n-1,'0'),k,visited);reverse(res.begin(),res.end());return string(n-1,'0')+res;}void dfs(string node, int k, unordered_set<string> &visited){for (char ch='0';ch<'0'+k;++ch){string newNode=node+ch;if (!visited.count(newNode)){visited.insert(newNode); dfs(newNode.substr(1),k,visited);res.push_back(ch);}}}
};

时间复杂度 O(k*k^n),因为每次找边的时候,是for循环枚举的。如果用链表或者别的方式存储,时间复杂度为 O(k^n)。纯粹是for循环更好些才这么做的。

Reference:

https://leetcode.com/problems/cracking-the-safe/discuss/110265/Having-trouble-understanding-it-Try-this.

转载于:https://www.cnblogs.com/hankunyan/p/11009810.html

LeetCode 753. Cracking the Safe相关推荐

  1. 【Leetcode】753. Cracking the Safe

    题目地址: https://leetcode.com/problems/cracking-the-safe/ 给定一个正整数nnn和一个正整数kkk,题目保证k<10k<10k<10 ...

  2. 753 Cracking the Safe

    方法一 Hierholzer's Algorithm 相关概念: 1 欧拉路径:在无向图中,每个边只经过一次,形成的路径.在有向图中,是指每条有向边只使用一次,形成的路径. 2 欧拉回路:欧拉路径是一 ...

  3. Leetcode 753. 破解保险箱 C++

    Leetcode 753. 破解保险箱 题目 有一个需要密码才能打开的保险箱.密码是 n 位数, 密码的每一位是 k 位序列 0, 1, -, k-1 中的一个 . 你可以随意输入密码,保险箱会自动记 ...

  4. leetcode 802. Find Eventual Safe States | 802. 找到最终的安全状态(有向图DFS)

    题目 https://leetcode.com/problems/find-eventual-safe-states/ 题解 用 circle 表示所有环上节点和所有能到达环的节点. DFS,实际上每 ...

  5. LeetCode之Find Eventual Safe States(Kotlin)

    问题: In a directed graph, we start at some node and every turn, walk along a directed edge of the gra ...

  6. Java实现 LeetCode 753 破解保险箱(递归)

    753. 破解保险箱 有一个需要密码才能打开的保险箱.密码是 n 位数, 密码的每一位是 k 位序列 0, 1, -, k-1 中的一个 . 你可以随意输入密码,保险箱会自动记住最后 n 位输入,如果 ...

  7. LeetCode 753. 破解保险箱(有向欧拉图,计算机译码)

    有一个需要密码才能打开的保险箱.密码是 n 位数, 密码的每一位是 k 位序列 0, 1, -, k-1 中的一个 . 你可以随意输入密码,保险箱会自动记住最后 n 位输入,如果匹配,则能够打开保险箱 ...

  8. taoqick 搜索自己CSDN博客

    L1 L2正则化和优化器的weight_decay参数 kaiming初始化的推导 Pytorch动态计算图 Pytorch自动微分机制 PyTorch中在反向传播前为什么要手动将梯度清零? 通俗讲解 ...

  9. leetcode刷题规划

    LeetCode精华题目列表[刷题规划系列] – TuringPlanet 目录 算法题到底在考察什么? 题目列表 Array String Linked List Queue Stack Advan ...

最新文章

  1. j.u.c.locks.AbstractQueuedSynchronizer.Node
  2. 如何在Vim中复制到剪贴板?
  3. 设计一个函数能够取出字符串中指定的字符
  4. java return none,返回列表结果为none
  5. hbase中的row key_hbase中RowKey的设计规则
  6. mysql5.7环境,MySQL-5.7-线上生产环境部署
  7. Windows Phone开发(29):隔离存储C 转:http://blog.csdn.net/tcjiaan/article/details/7447469...
  8. intellij idea 中去除 @Autowired 注入对象带来的红色下划线报错提示
  9. apache 支持.htaccess重写url
  10. PyCharm+Python3转换xls文件为xlsx文件格式
  11. 运算器为计算机提供了计算与逻辑,【单选题】运算器为计算机提供了计算与逻辑功能,因此称它为()....
  12. 《图形学》实验一:钻石图案
  13. java.net.SocketException: Connection reset 问题分析
  14. Arduino: AD模数转换详解和电路搭建以及示例代码
  15. 计算机科学与技术用惠普星15,11代酷睿满血出击 快来GET蔡徐坤同款惠普星14吧...
  16. 【资源】DNW驱动,Win7 64位可用
  17. XML文档定义有几种形式?解析XML文档有哪几种方式?
  18. git pull 时每次都要输入用户名和密码的解决办法
  19. php 路由器设置密码,为防蹭网宽带密码修改之后无线路由器设置教程
  20. linux c编程文件枷锁

热门文章

  1. android开发项目app实例!我在华为做Android外包的真实经历!深度好文
  2. 管链输送机压链板及盘片的使用……
  3. 2020年小红书校招数据分析笔试题
  4. 怎样修复win10计算机系统,教你怎么使用win10系统修复工具教程
  5. 最新web前端面试题
  6. minipcie接口can卡,工控机或单板电脑扩展CAN通道的佳选
  7. DeepWalk模型的简介与优缺点
  8. 认识工业防火墙硬件架构
  9. python血压测量程序代码_血压测量程序及评价标准
  10. JVM笔记-13运行时数据区-堆(OOM、年轻代老年代)