楼主: 神罗天征
跳转到指定楼层
上一主题 下一主题
收起左侧

Google面经题密码箱问题解法求问

🔗
dietpepsi 2016-1-24 17:01:12 | 只看该作者
全局:
本帖最后由 dietpepsi 于 2016-1-24 18:19 编辑

不是很明白题意,如果说是一个4位的行李箱要破解密码的话,每次动一位的解法和debruijn序列不一致啊
如果答案是debruijn序列的话,说明题意是一个类似于sliding window的输入框,前面的数字会自动被挤出去然后后面键入的数字可以是0-9中的任意一个。

所以题里到底说的是怎样的密码锁


是不是跟这道题一样的
http://www.careercup.com/question?id=5126565916573696
回复

使用道具 举报

🔗
stellari 2016-1-24 19:12:04 | 只看该作者
全局:
dietpepsi 发表于 2016-1-24 17:01
不是很明白题意,如果说是一个4位的行李箱要破解密码的话,每次动一位的解法和debruijn序列不一致啊
如果 ...

我想楼主(@神罗天征)问的这道题应该是“sliding window”的那种情况。否则,他说的“包含所有的4位数序列,让这个序列尽可能短”这句话就没有意义了。但是,楼上@skye_luobopi提到的那道3位密码锁题则是另外一种情况。
回复

使用道具 举报

🔗
dietpepsi 2016-1-25 08:03:21 | 只看该作者
全局:
stellari 发表于 2016-1-24 19:12
我想楼主(@神罗天征)问的这道题应该是“sliding window”的那种情况。否则,他说的“包含所有的4位数序 ...

妥~,那我就明白了~
所以那这题就是在得在一个3位deBruijin图上找一个欧拉回路。每一个点有10个出度10个入度,一共1000个vertices和10000条edge。 不用Lyndon words的知识应该也可以构造出来。效率肯定比最优解低,但应该比Brute Force DFS快。
回复

使用道具 举报

🔗
stellari 2016-1-25 09:20:35 | 只看该作者
全局:
dietpepsi 发表于 2016-1-25 08:03
妥~,那我就明白了~
所以那这题就是在得在一个3位deBruijin图上找一个欧拉回路。每一个点有10个出度10个 ...

我之前贴的那段代码其实本质上就是在4维de Bruijn图上找Hamilton回路,和3维de Bruijn上的欧拉回路是一个意思。但是,这是在我已知de Bruijn是Hamiltonian的情况下写出的代码。如果是面试的时候,假设我之前从没有听说过de Bruijn,如何快速向面试官说明de Bruijn图是Hamiltonian或者Eulerian呢?
回复

使用道具 举报

🔗
dietpepsi 2016-1-25 09:37:07 | 只看该作者
全局:
本帖最后由 dietpepsi 于 2016-1-25 14:51 编辑
stellari 发表于 2016-1-25 09:20
我之前贴的那段代码其实本质上就是在4维de Bruijn图上找Hamilton回路,和3维de Bruijn上的欧拉回路是一个 ...

找欧拉回路有非常简单的Hierholzer算法,代码就这几行。我跟deBruijn对比过,是正确的。这里面为了和deBruijn答案相近我把结果reverse了,不reverse肯定也是有效答案。不过这个写法计算k = 10 n = 4会出现stackoverflow. 需要设置-Xss2m或以上。
  1. public class EulerSolution {
  2.     int n, k, v;
  3.     boolean[][] visited;
  4.     StringBuilder sequence;

  5.     public String crackSequence(int k, int n) {
  6.         this.n = n;
  7.         this.k = k;
  8.         v = (int)Math.pow(k, n - 1); // vertices are n-1 bit radix k number.
  9.         visited = new boolean[v][k]; // edge list
  10.         sequence = new StringBuilder();
  11.         dfs(0);
  12.         return sequence.reverse().toString();
  13.     }

  14.     private void dfs(int u) {
  15.         for (int i = 0; i < k; ++i) {
  16.             if (!visited[u][i]) {
  17.                 visited[u][i] = true;
  18.                 dfs((u * k + i) % v);
  19.                 sequence.append(i);
  20.             }
  21.         }
  22.     }
  23. }
复制代码
回复

使用道具 举报

🔗
dietpepsi 2016-1-25 09:47:08 | 只看该作者
全局:
本帖最后由 dietpepsi 于 2016-1-25 10:01 编辑

我觉得这道题在题意明确的情况下,把所有状态看成点,状态之间的转移看成边是比较自然的。
这样就有两种看法,一种就是把4位看成状态,一种就是把3位看成状态。
把4位看成状态的图上面找Hamilton回路,很显然是本题的答案,因为访问了每一个节点一次且只有一次。
把3位看成状态的图上面找欧拉回路可能需要给面试官解释一下。但我觉得还是比较好解释的。
因为每一条边其实代表了一种4位的状态,于是就很好解释了。
那么上面的DFS找欧拉回路的算法就是相当简单有效的解法了。在删除边和查找下一个没有访问的边的复杂度是O(1)的情况下这个算法的复杂度是O(E)的,也就是O(k^n)的,de Buijin构造算法不会比这个复杂度更好。
我这个实现没有用LinkedList或者Hash来保存边的信息,所以每次都是循环所有可能的边,也就是O(k)查找边,所以总的复杂度是O(k^(n+1))。
考虑到
k = 10 n = 4
我觉得没啥问题。




回复

使用道具 举报

🔗
dietpepsi 2016-1-25 09:51:05 | 只看该作者
全局:
证明这个图是欧拉的非常容易,因为有向图,每一个节点的入度和出度都相等,必然是欧拉图。
回复

使用道具 举报

🔗
dietpepsi 2016-1-25 14:08:14 | 只看该作者
全局:
本帖最后由 dietpepsi 于 2016-1-25 14:46 编辑

这个写法更好,复杂度完全是O(E)了,不过对(10,4)还是会stackoverflow。设置-Xss2m或以上就可以,貌似不是啥大问题。
  1. public class EulerSolution {
  2.     int n, k, v;
  3.     int[] edge;
  4.     StringBuilder sequence;

  5.     public String crackSequence(int k, int n) {
  6.         this.n = n;
  7.         this.k = k;
  8.         v = 1; for (int i = 0; i < n - 1; ++i) v *= k; // vertices are n-1 bit radix k number.
  9.         edge = new int[v]; // edge list
  10.         sequence = new StringBuilder();
  11.         dfs(0);
  12. //        for (int i = 0; i < n - 1; ++i) sequence.append(0);
  13.         return sequence.reverse().toString();
  14.     }

  15.     // Hierholzer's algorithm
  16.     private void dfs(int u) {
  17.         while (edge[u] != k) {
  18.             int i = edge[u]++;
  19.             dfs((u * k + i) % v);
  20.             sequence.append(i);
  21.         }
  22.     }

  23.     public static void main(String[] args) {
  24.         System.out.println(new EulerSolution().crackSequence(9, 4).length());
  25.     }
  26. }
复制代码
回复

使用道具 举报

🔗
dietpepsi 2016-1-25 14:12:45 | 只看该作者
全局:
本帖最后由 dietpepsi 于 2016-1-25 14:51 编辑

改写成Iterative,避免了全局变量,复杂度O(E) = O(k^n)
  1. public class IterativeEulerSolution {

  2.     // Hierholzer's algorithm
  3.     public String crackSequence(int k, int n) {
  4.         int v = 1;
  5.         for (int i = 0; i < n - 1; ++i) v *= k; // vertices are n-1 bit radix k number.
  6.         int[] edge = new int[v];
  7.         StringBuilder sequence = new StringBuilder();
  8.         
  9.         int u = 0, i = 0;
  10.         Deque<Integer[]> stack = new ArrayDeque<>();
  11.         while (true) {
  12.             if (i == k) {
  13.                 if (stack.isEmpty()) break;
  14.                 Integer[] t = stack.pop();
  15.                 u = t[0];
  16.                 sequence.append(t[1]);
  17.                 i = edge[u];
  18.             } else {
  19.                 stack.push(new Integer[]{u, i});
  20.                 edge[u]++;
  21.                 u = (u * k + i) % v;
  22.                 i = edge[u];
  23.             }
  24.         }

  25. //        for (int i = 0; i < n - 1; ++i) sequence.append(0);
  26.         return sequence.reverse().toString();
  27.     }

  28.     public static void main(String[] args) {
  29.         System.out.println(new IterativeEulerSolution().crackSequence(10, 4).length());
  30.     }
  31. }
复制代码
回复

使用道具 举报

🔗
dietpepsi 2016-1-25 14:50:29 | 只看该作者
全局:
来一发Benchmark~
  1. // (k,n)      de Bruijin       recursive-euler        iterative-euler
  2. // (2,2)      0.094 ms         0.031 ms               0.121 ms
  3. // (2,4)      0.105 ms         0.041 ms               0.131 ms
  4. // (2,8)      0.427 ms         0.165 ms               0.888 ms
  5. // (4,2)      0.230 ms         0.044 ms               0.132 ms
  6. // (4,4)      0.297 ms         0.174 ms               0.651 ms
  7. // (4,6)      2.091 ms         1.098 ms               5.627 ms
  8. // (8,2)      0.155 ms         0.055 ms               0.179 ms
  9. // (8,4)      1.831 ms         0.993 ms               9.783 ms
  10. // (10,4)     4.405 ms         1.848 ms              13.556 ms
  11. // (20,4)    17.316 ms        55.785 ms              71.769 ms
  12. // (10,6)    48.535 ms        79.245 ms             270.148 ms
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表