九宮格手機解鎖有多少種情況?
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/