九宫格手机解锁有多少种情况?
2016-07-02 00:12
645 查看
0、写在前面:
本文的内容大概搬运自果壳和知乎的两篇文章,在结尾有注明参考。
安卓手势解锁是安卓手机解除锁定的密码方案,究竟这种方式一定有多少种可能呢?这是本文要讨论的问题。
至少连接点阵中的四个点。
手势的轨迹不能跨过一个还没有经过的节点。
不允许重复经过某个定点两次。
去掉第二个限制条件,一种解锁手势正好对应一种1到9的排列。连接四个点的解锁手势的所有情况就是9选4的全排列,连接5个点的就是9选5的全排列,以此类推。
计算全排列的比较容易,接下来要解决的就是如何剔除那些不符合限制条件(手势的轨迹不能跨过一个还没有经过的节点)的手势。在3*3的点阵中,不符合条件的情况(也就是两个点的连接过程中跨过点的情况)比较有限,这里我们将其全部列出。
上面可以看出,这种情况主要有16中(每种用一个k-v对来表示)。每一对列出了跨过点的情况,比如13连接会跨过2。
下面通过程序用全排列的思路列举出所有可能的手势情况,用一个数字字符串表示,并剔除掉其中不符合条件。剔除的思路很简单:对于每一种k-v对表示的跨过点的情况,如果k和v在表示手势的字符串中出现,并且没有出现在k出现的位置之前,那么这种情况应该被剔除。下面是代码(Python):
最后,程序运行的结果是一共有389112中情况。
结果如下:
由此可见,该密码空间的绝大部分分布在连接8到9个点的情况。我们大部分人的手势密码都之后连接4到5个点,而这部分的搜索空间只有8776中可能,也就大概相当于4位数字密码的强度。
参考:
知乎
果壳网
本文的内容大概搬运自果壳和知乎的两篇文章,在结尾有注明参考。
安卓手势解锁是安卓手机解除锁定的密码方案,究竟这种方式一定有多少种可能呢?这是本文要讨论的问题。
1、问题定义
问题很简单:安卓的手势解锁是3*3的点阵,在这个点阵上的解锁手势一共有多少种情况?这里一个合格的解锁手势轨迹必须满足以下两个条件:至少连接点阵中的四个点。
手势的轨迹不能跨过一个还没有经过的节点。
不允许重复经过某个定点两次。
2、问题转化
为了方便,这里将点阵中的每个点用一个数字代替,1到9九个数字分别代表点阵中的一个点。这样,一个解锁手势可以对应到一个由1到9数字组成的字符串(该字符串中没有重复)。去掉第二个限制条件,一种解锁手势正好对应一种1到9的排列。连接四个点的解锁手势的所有情况就是9选4的全排列,连接5个点的就是9选5的全排列,以此类推。
计算全排列的比较容易,接下来要解决的就是如何剔除那些不符合限制条件(手势的轨迹不能跨过一个还没有经过的节点)的手势。在3*3的点阵中,不符合条件的情况(也就是两个点的连接过程中跨过点的情况)比较有限,这里我们将其全部列出。
'13': '2', '46': '5', '79': '8', '17': '4', '28': '5', '39': '6', '19': '5', '37': '5', '31': '2', '64': '5', '97': '8', '71': '4', '82': '5', '93': '6', '91': '5', '73': '5'
上面可以看出,这种情况主要有16中(每种用一个k-v对来表示)。每一对列出了跨过点的情况,比如13连接会跨过2。
下面通过程序用全排列的思路列举出所有可能的手势情况,用一个数字字符串表示,并剔除掉其中不符合条件。剔除的思路很简单:对于每一种k-v对表示的跨过点的情况,如果k和v在表示手势的字符串中出现,并且没有出现在k出现的位置之前,那么这种情况应该被剔除。下面是代码(Python):
from itertools import chain, permutations impossible = {'13': '2', '46': '5', '79': '8', '17': '4', '28': '5', '39': '6', '19': '5', '37': '5', '31': '2', '64': '5', '97': '8', '71': '4', '82': '5', '93': '6', '91': '5', '73': '5'} def counts(): count = 0 all_list = chain(*(permutations('123456789', i) for i in range(4, 9 + 1))) for e in all_list: e_str = ''.join(e) for k,v in impossible.items(): if k in e_str and v not in e_str[:e_str.find(k)]: break else: count = count + 1 return count print(counts())#389112
最后,程序运行的结果是一共有389112中情况。
3、进一步分析
下面稍微修改下程序,这些手势情况在不同的长度中是如何分布的?from itertools import chain, permutations impossible = {'13': '2', '46': '5', '79': '8', '17': '4', '28': '5', '39': '6', '19': '5', '37': '5', '31': '2', '64': '5', '97': '8', '71': '4', '82': '5', '93': '6', '91': '5', '73': '5'} def counts_n(n): iterlst = permutations('123456789', n) count = 0 for i in iterlst: stri = ''.join(i) for k, v in impossible.items(): if k in stri and v not in stri[:stri.find(k)]: break else: count += 1 return count sum = 0 print("len num sum") for i in range(4,10): temp = counts_n(i) sum = sum + temp print(str(i)+" "+str(temp)+" "+str(sum))
结果如下:
len num sum 4 1624 1624 5 7152 8776 6 26016 34792 7 72912 107704 8 140704 248408 9 140704 389112
由此可见,该密码空间的绝大部分分布在连接8到9个点的情况。我们大部分人的手势密码都之后连接4到5个点,而这部分的搜索空间只有8776中可能,也就大概相当于4位数字密码的强度。
参考:
知乎
https://www.zhihu.com/question/24905007/answer/29414497
果壳网
http://www.guokr.com/article/49408/
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- C#算法函数:获取一个字符串中的最大长度的数字
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法