vivo2020届春季校园招聘在线编程考试
vivo2020届春季校园招聘在线编程考试
[编程题]手机屏幕解锁模式
现有一个 3x3 规格的 Android 智能手机锁屏程序和两个正整数 m 和 n ,请计算出使用最少m 个键和最多 n个键可以解锁该屏幕的所有有效模式总数。
其中有效模式是指:
1、每个模式必须连接至少m个键和最多n个键;
2、所有的键都必须是不同的;
3、如果在模式中连接两个连续键的行通过任何其他键,则其他键必须在模式中选择,不允许跳过非选择键(如图);
4、顺序相关,单键有效(这里可能跟部分手机不同)。
输入:m,n
代表允许解锁的最少m个键和最多n个键
输出:
满足m和n个键数的所有有效模式的总数
输入例子1:
1,2
输入例子1:
56
输入例子1:
输入m=1,n=2,表示最少1个键,最多2个键,符合要求的键数是1个键和2个键,其中1个键的有效模式有9种,两个键的有效模式有56种,所以最终有效模式总数是9+56=65种,最终输出65。
用Java解题,算出所有可能性包括无效的模式,如285是无效的,而528是有效的。
在编写过程中,我突然发现其实输入9,9其实和8,8是一样的可能性,也就是其实8和9就是一样可能性的,因为最后9x8x7x6x5x4x3x2=9x8x7x6x5x4x3x2x1。也就是说输入1,9其实等于1,8加上8,8的所有可能性。
代码如下 代码片
.
// An highlighted block
//默认是flase,如果为true代表被选择。
public static boolean select[] = new boolean[10];
//写出所有无效的路线
public static String numberStr[] ={"13","19","17","31","91","71","39","37","93","73","79","97","46","64","82","28"};
//与无效路线集合下标对应,值为穿过的点
public static String pont[] ={"2","5","4","2","5","4","6","5","6","5","8","8","5","5","5","5"};
public static int solution (int m, int n){
if(n<0||n-m<0) {
return 0;
}
int tot =0;
if(n==9&&m<9||n>9&&m<9){
tot=allselect(m,n)-(4*cal(m,8,1,1,"")+4*cal(m,8,2,1,"")+cal(m,8,5,1,""))-(4*cal(8,8,1,1,"")+4*cal(8,8,2,1,"")+cal(8,8,5,1,""));
}else {
// 1 3 7 9 类似情况合并 2 4 6 8 类似情况合并 5又是一种情况
if(n==9&&m==9){
n =8;
m =8;
}
tot=allselect(m,n)-(4*cal(m,n,1,1,"")+4*cal(m,n,2,1,"")+cal(m,n,5,1,""));;
}
return tot;
}
public static int allselect(int m,int n){
int total = 0;
int initM= m;
int initN = n;
int maxSelect =9;
if(n<m ||n==0){
return 0;
}
if(n>9){
initN = 9;
}
while (initM>0){
if(total==0){
total= maxSelect;
}else{
total =maxSelect*total;
}
maxSelect = maxSelect-1;
initM--;
}
if((m+1)<=initN){
total = total+ allselect(m+1,initN);
}
return total;
}
public static int cal(int m,int n,int start,int end,String str){
String path = str+start;
int count = 0;
if(end>n){
return 0;
}
if(end>=m&&path.length()>1&&end<n){
// System.out.println(path);
int j =0;
boolean isFound = false;
while (j<numberStr.length&&!isFound){
if(path.indexOf(numberStr[j])>=0){
if(path.indexOf(pont[j])==-1||path.indexOf(pont[j])>path.indexOf(numberStr[j])){
isFound =true;
count++;
}
}
j++;
}
}
select[start] =true;
for(int i =1;i<10;i++){
if(!select[i]&&end<n){
count = count+cal(m,n,i,end+1,path);
}
if(!select[i]&&end==n&&n>1){
int j =0;
boolean isFound = false;
while (j<numberStr.length&&isFound==false){
if(path.indexOf(numberStr[j])>=0){
if(path.indexOf(pont[j])==-1||path.indexOf(pont[j])>path.indexOf(numberStr[j])){
count++;
select[start] =false;
return count;
}
}
j++;
}
}
}
select[start] =false;
return count;
}
该方法参考了https://blog.csdn.net/weixin_42241455/article/details/105168526中的解题思路,不同的是本方法是算所有可能性包括无效模式再减去无效的模式,参考方法是直接计算所有有效的模式。