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/