题目:
手机屏幕解锁模式
现有一个 3x3 规格的 Android 智能手机锁屏程序和两个正整数 m 和 n ,请计算出使用最少m 个键和最多 n个键可以解锁该屏幕的所有有效模式总数。
其中有效模式是指:
1、每个模式必须连接至少m个键和最多n个键;
2、所有的键都必须是不同的;
3、如果在模式中连接两个连续键的行通过任何其他键,则其他键必须在模式中选择,不允许跳过非选择键(如图);
4、顺序相关,单键有效(这里可能跟部分手机不同)。
输入:m,n
代表允许解锁的最少m个键和最多n个键
输出:
满足m和n个键数的所有有效模式的总数
示例1
输入例子: 1,2
输出例子: 65 例子说明:
输入m=1,n=2,表示最少1个键,最多2个键,符合要求的键数是1个键和2个键,其中1个键的有效模式有9种,两个键的有效模式有56种,所以最终有效模式总数是9+56=65种,最终输出65。
解题思路:
需要使用深度优先搜索(DFS)来遍历不同的解锁模式,并计算满足条件的模式数量,在遍历不同的起始点和连接不同数量的点时,使用了规则来判断有效的连接路径。
countPatterns方法:输入参数m和n,代表允许解锁的最少和最多键数,计算满足在范围[m,n]内允许的键数的所有有效模式的总数。
对于每个起始点(1,2和5),我们调用 dfs
方法,从该起始点开始,考虑连接 i - 1
个点的情况。疑问:为什么从1,2,5出发,其他点不要考虑吗?
- 由于(1,3,7,9)角落点可以从四个不同的起始位置开始,它们连接其它点时会经过中间的点,所以我们乘以 4。
- 对于从边上的点出发(2,4,6,8),它们不一定经过中间的点,所以也要乘4。
- 对于中间点5,只需要考虑一种起始位置。
- 所有这些结果累加起来,就得到在给定范围内满足条件的有效模式总数。
isValidPattern方法:输入参数:curr和next,代表当前键和下一个键的数字。该方法用于检查给定的当前键和下一个键是否构成有效的解锁模式。
dfs方法:输入参数:curr和remaining,代表当前键和剩余要连接的键数,该方法是一个深度优先搜索(DFS)的递归函数,用于计算在给定的键数限制下,从当前键开始的所有有效解锁模式的数量。
代码:
import java.util.*;
public class Solution {
/**
* 实现方案
* @param m int整型 最少m个键
* @param n int整型 最多n个键
* @return int整型
*/
private int [][]skip;//二维数组,表示两个键之间有需要跳过的键
private boolean[] visited;//记录每个点是否已经被访问过
public int solution (int m, int n) {
// write code here
skip = new int[10][10]; //
skip[1][3] =skip[3][1] = 2;//表示键1和3之间有一个键2需要跳过,下面的以此类推
skip[1][7] =skip[7][1] = 4;
skip[3][9] = skip[9][3] = 6;
skip[7][9] = skip[9][7] = 8;
skip[1][9] = skip[9][1] = skip[3][7] = skip[7][3] = skip[2][8] = skip[8][2] = skip[4][6]= skip[6][4]= 5;
visited = new boolean[10];
int totalCount = 0;
for(int i=m;i<=n;i++){
totalCount += dfs(1,i-1)*4;//
totalCount += dfs(6,i-1)*4;
totalCount += dfs(5,i-1);
}
return totalCount;
}
private boolean isValidPattern(int curr,int next){
if(visited[next]){
return false; //如为真,代表已经被访问了
}
if(skip[curr][next]==0||visited[skip[curr][next]]){
return true;
}
return false;
}
private int dfs(int curr,int remaining){
if(remaining<0){
return 0; //代表没有剩余要连接的点
}
if(remaining==0){
return 1;
}
visited[curr] = true;
int count = 0;
for(int next=1;next<=9;next++){
if(isValidPattern(curr,next)){
count += dfs(next,remaining-1);
}
}
visited[curr] = false;
return count;
}
}