Given an Android 3x3 key lock screen and two integers m and n, where 1 ≤ m ≤ n ≤ 9, count the total number of unlock patterns of the Android lock screen, which consist of minimum of m keys and maximum n keys.
Rules for a valid pattern:
1. Each pattern must connect at least m keys and at most n keys.
2. All the keys must be distinct.
3. If the line connecting two consecutive keys in the pattern passes through any other keys, the other keys must have previously selected in the pattern. No jumps through non selected key is allowed.
4. The order of keys used matters.
android unlock
Explanation:
| 1 | 2 | 3 |
| 4 | 5 | 6 |
| 7 | 8 | 9 |
Invalid move: 4 - 1 - 3 - 6
Line 1 - 3 passes through key 2 which had not been selected in the pattern.
Invalid move: 4 - 1 - 9 - 2
Line 1 - 9 passes through key 5 which had not been selected in the pattern.
Valid move: 2 - 4 - 1 - 3 - 6
Line 1 - 3 is valid because it passes through key 2, which had been selected in the pattern
Valid move: 6 - 5 - 4 - 1 - 9 - 2
Line 1 - 9 is valid because it passes through key 5, which had been selected in the pattern.
样例
Given m = 1, n = 1, return 9.
思路
| 1 | 2 | 3 |
| 4 | 5 | 6 |
| 7 | 8 | 9 |
对于上述键盘,总结出如下规则:
1、7需要中间键4,2、8需要中间键5,3、9需要中间键6,
1、3需要中间键2,4、6需要中间键5,7、9需要中间键8,
1、9和3、7需要中间键5(包括相反的情况1、9–>9、1)
其余情况均不需要中间的键值(困惑在于2,7之间也不需要)。
之后,深度遍历一个键值,得到它能够成的最多图案数。由于键盘的对称性,1,3,7,9得到的图案数相同,2,4,6,8得到的图案数相同,5单独计算。
#ifndef C909_H
#define C909_H
#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
int numberOfPatterns(int m, int n) {
int res = 0;
vector<bool> visited(10, false);
vector<vector<int>> keyboard(10, vector<int>(10, 0));//keyboard[i][j]表示从i跳转到j中间需要键值
//根据规则初始化跳转矩阵的键值
keyboard[1][3] = keyboard[3][1] = 2;
keyboard[4][6] = keyboard[6][4] = 5;
keyboard[7][9] = keyboard[9][7] = 8;
keyboard[1][7] = keyboard[7][1] = 4;
keyboard[2][8] = keyboard[8][2] = 5;
keyboard[3][9] = keyboard[9][3] = 6;
keyboard[1][9] = keyboard[9][1] = keyboard[3][7] = keyboard[7][3] = 5;
//由对称性可得,1,3,7,9值相同;2,4,6,8值相同;5独自求值
res += helper(1, 1, m, n, keyboard, visited) * 4;
res += helper(2, 1, m, n, keyboard, visited) * 4;
res += helper(5, 1, m, n, keyboard, visited);
return res;
}
//从num开始深度遍历跳转矩阵keyboard
//遍历1~9,找出可以直接到达的键和中间键已经被访问的键,添加到最终结果
int helper(int num, int len, int m, int n, vector<vector<int>> &keyboard, vector<bool> visited)
{
int res = 0;
if (len >= m)
res++;
++len;
if (len > n)
return res;
visited[num] = true;
for (int i = 1; i <= 9; ++i)
{
int mid = keyboard[num][i];
if (!visited[i] && (mid == 0 || visited[mid]))
{
res += helper(i, len, m, n, keyboard, visited);
}
}
visited[num] = false;
return res;
}
};
#endif