您的位置:首页 > 其它

九宫格手机解锁有多少种情况?

2016-07-02 00:12 645 查看
0、写在前面:

本文的内容大概搬运自果壳知乎的两篇文章,在结尾有注明参考。

安卓手势解锁是安卓手机解除锁定的密码方案,究竟这种方式一定有多少种可能呢?这是本文要讨论的问题。

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/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法