android 手机屏幕解锁最多有多少种?

 

这个十分有趣的题目出自知乎http://www.zhihu.com/question/24905007/answer/29414497 ,排名第一的知友的答案用python简洁的给出了代码和答案,枉费我用C++ 鼓捣了半天。。。

不过也不能算是白做,还是有颇多收获的。



先准确描述一下这个问题解决思路:

这题目本质就是计算排列:

定义一个函数 permutation(n.m) :从n个数中选m个进行全排列

我们要计算的就是

       1. Σ permutation(9,i) (i从1到9)

          结果等于3024+15120+60480+181440+362880+362880=985824

2. 然后剔除特殊情况:

   13或31出现在2之前

    17或71出现在4之前

    19或91出现在5之前

    37或73出现在5之前

    79或97出现在8之前

    28或82出现在7之前

    46或64出现在5之前


下面从头分析:

 

乍看问题,这一定是一个排列问题,但是这里存在两个容易遇到的麻烦:

1. 但我们一般实现的都是全排列,所以第一个问题就是 如何由全排列计算排列。

2. 还有一个问题,大多数人实现的全排列并没有真的实现排列,只是借助递归栈来达到输出所有排列,这个差异是很大的,我们仅仅输出是不够的,我们应该将每种记录下来,然后进行排除。

第一个问题如何解决:

我在百般尝试后,求助于STL ,发现STL 中也只有一个next_permutation(字典序全排列的下一个),并没有实现普通排列和组合。

这提示我: 既然标准库只提供一个全排列,说明排列可以很容易从全排列那里获取,事实上这一点也和我们的直觉符合,经过验证和分析:

我认为这个问题是这样的:

针对字典序的全排列,我们要求next_permutation(n,m)需要借助next_permutation(n)//全排列函数

步骤如下:

     l 将容器[m,n)逆序,然后求next_permutation;

            l 此时[0,m)即为next_permutation

原理也很简单,就是利用了字典序的特点,为什么可以这样做,其实是因为当我们做全排列的时候其实信息是最大的,我们自然可以从中剖析出规模更小的排列

第二个问题:

由于我自己以前实现的全排列函数就可以直接将所有结果保存在一个vector里面,因此本来是不存在这个问题的。这不是一个算法的问题,是一个设计的问题,但这个问题也可以很复杂,视全排列函数的实现而异。

先展示一下 python 代码:(来源是知乎上述网址,我对其命名进行一些改动,方便理解)

#python
from itertools import *

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 count_unlock_screen():
    bucket = chain(*(permutations(‘123456789‘, i) for i in range(4, 10)))
    count = 0
    for i in bucket:
        striter = ‘‘.join(i)
        for key, value in impossible.items():
            if key in striter and value not in striter[:striter.find(key)]:
                break
        else:
            count += 1
    return count

print( count_unlock_screen() )
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

bool legal(string left, string right, string mid, string &a)
{
    string test1 = left + right;
    string test2 = right + left;
    string::size_type p1 = a.find(test1);
    string::size_type p2 = a.find(test2);
    string::size_type q = a.find(mid);

    if ((p1 != string::npos) && (q == string::npos))
        return false;
    if ((p2 != string::npos) && (q == string::npos))
        return false;
    if((p1 != string::npos) && q > p1)
        return false;
    if ((p2 != string::npos) && q > p2)
        return false;
    return true;
}

bool is_legal(string &a)
{
    string::size_type p = string::npos;
    string one("1");string two("2");string three("3");
    string four("4"); string five("5"); string six("6");
    string seven("7"); string eight("8"); string nine("9");
    if ((!legal(one, three, two, a)) || (!legal(one, seven, four, a)) || (!legal(one, nine, five, a)) || (!legal(three, seven, five, a)) || (!legal(three, nine, six, a)) || (!legal(seven, nine, eight, a))||(!legal(two, eight, five, a))||(!legal(four, six, five, a)))
        return false;
    else return true;
}
void swap(char &index1, char &index2)
{
    char temp = index1;
    index1 = index2;
    index2 = temp;
}

//全排列中的下一个
bool next_permutation(string &a)
{
    int i = 0;
    int size = a.size();
    for (i = size - 2; i >= 0; i--)            //从size开始找到第一个满足a[i] < a[i+1]的位置i
    {
        if (a[i] < a[i + 1])
            break;
    }
    if (i == -1)                            //寻找结束后若i=-1说明当前的a数组已经达到字典序的最大
    {
        return true;
    }
    int j = i + 1;                            //j用于遍历i---n之间的元素
    int min_larger = j;                       //min_larger存储i---n之间满足  a[min_larger] > a[j] 中的最小者,由于之前i循环中判断得知a[i+1]一定大于a[i]
    //因此,将min_larger初始化为i+1
    while (j < size &&  a[j] > a[i])
    {
        if (a[min_larger] > a[j])
            min_larger = j;
        j++;
    }

    swap(a[i], a[min_larger]);
    string::iterator kb = a.begin() + i + 1;
    string::iterator ke = a.end();
    reverse(kb, ke);

       return false;

}

//计算下一个排列数
bool next_k_permutation(string &a,int length,string &result)
{
    reverse(a.begin() + length, a.end());

    if (!next_permutation(a))
    {
        string ss(a, 0, length);
        result = ss;
        return true;
    }
      return false;

}

void count_all(string&a)
{
    int length = a.size();

    int count = 0;

    while (length >= 4)
    {
        sort(a.begin(), a.end());
        count++;
        string result;
        while (next_k_permutation(a, length,result))
        {
            if (is_legal(result))
            {
                count++;

            }
        }

        --length;

    }

    cout << count << endl;
}

int main()
{
    string s = "123456789";

    count_all(s);

    system("pause");
    return 0;
}

 

python 代码运行效率确实很快,对于如此大量的计算,几秒中之内就可以给出结果。说明python的数据结构和库 优化还是很好的,对比我自己实现的C++ 方案明显要快的多,显然不是说C++ 效率比较低,但C++ 对于字符串处理的确非常麻烦,我也没有过多的针对性优化,所以运行就比较慢了,但结果是正确的。

这个问题还是非常有趣的,但是其实还是蛮难的,尝试用数学直接手算但是放弃了,排除实在比较麻烦,还是借助计算机啦!

android 手机屏幕解锁最多有多少种?

时间: 2024-10-07 17:56:54

android 手机屏幕解锁最多有多少种?的相关文章

Unity3D Android手机屏幕分辨率问题

Android手机屏幕分辨率五花八门,导致开发时不好把握,还好各个引擎对这个屏幕分辨率问题都有较好的处理方式:unity3D 也为我们提供了一个不错的解决方案. 在Unity3D 进行 android 游戏开发时,对于不同分辨率下的显示效果就像是摄像机的自动平移了一般,看了不少游戏,对于 Unity3D 开发 android 游戏貌似都没有做相应的屏幕分辨率的处理,而是随摄像机的自动移动,把场景做大些不至于出现空白背景. 其实 Unity3D 开发3D游戏,对于不同的分辨率,我们只需要设置 1

android 使用asm.jar将android手机屏幕投影到电脑上

使用asm.jar将Android手机屏幕投影到电脑 有时候可能需要将手机上的一些操作投影出来,比如一些App Demo的展示等.其实,有专门的硬件设备能干这件事儿,但没必要专门为展示个Demo去花钱买硬件设备.正好,对于Android系统的手机,有一个开源的jar包能干这事儿:Android Screen Monitor(asm.jar),官网 https://code.google.com/p/android-screen-monitor/  . 1.到官网下载ASM的zip包,解压后得到a

终结者:电脑显示Android手机屏幕之asm.jar工具正确的使用方法

1.asm.jar的作用: 提到asm.jar的作用,那么最显著的莫过于计算机显示Android手机屏幕了:其次可以调整计算机上显示Android手机屏幕的大小(好多人都没有发现这个功能):再者可以选择不同的显示的Android手机设备:还可以设置手机显示屏幕的方向:还可以截取手机的屏幕:等等等. 2.下载asm.jar: 网上下载asm.jar的链接有很多,但需要说明的是有一些是病毒,这里提供一个安全的下载链接地址(下载下来的压缩文件不仅包含了asm.jar,而且还有其实现的源码):http:

Android手机屏幕投射到电脑神器Vysor

做android开发的,经常要把手机屏幕投射到电脑,用来演示.普遍的解决方案是360或者豌豆荚的演示功能,缺点是延迟非常厉害,大概有3秒左右,非常影响演示效果.以下介绍Vysor,几乎0延迟,能与手机画面同步 Vysor是chrome浏览器的应用,因此先要下载原版的chrome,并且还要使用chrome应用商店,如何fq使用应用商店大家可以百度 软件打开后是这么个样子 PS:win10要安装最新的ADB驱动,软件界面下方有提供下载链接 然后是手机的准备,首先,开启usb调试模式 然后用usb线把

Android手机屏幕流畅投影到电脑进行演示(无需Root)

最近要在公司的会议上演示App,需要在投影仪上显示出来给大家演示.由于投影仪不是智能投影仪,只能将App先投影到自己的笔记本上,然后再将笔记本上的内容投影到投影仪上.该App是个游戏,实时交互性比较高,之前试过一些各种手机助手,比如腾讯的应用宝.360手机助手.豌豆荚手机助手等,这些手机助手可以在电脑上显示手机屏幕,但是非常卡顿,基本没法演示游戏App.我的手机是小米Note,最开始的时候用的是Android 4.4的系统,当时可以用小米助手链接小米Note,小米助手可以在PC上相对来说比较流畅

[email&#160;protected]:在PC屏幕上显示Android手机屏幕

这里介绍一款工具——[email protected],用来获取手机屏幕,显示在PC屏幕上.它集截图.录像等多种功能于一体. 安装 1.    下载地址:http://droid-at-screen.org/download.html,下载后是一个jar包,放到某个目录就可以. 2.    安装JDK6或以上版本 3.    安装Android SDK(从Android官方下载一个完整包解压即可) 4.    设置ANDROID_HOME环境变量指向AndroidSDK主目录(这步如果不做,则需

android 使用asm.jar将android手机屏幕投射到电脑

使用asm.jar将Android手机到电脑屏幕投影 有时候可能须要将手机上的一些操作投影出来,比方一些App Demo的展示等.事实上,有专门的硬件设备能干这件事儿.但不是必需专门为展示个Demo去花钱买硬件设备.正好,对于Android系统的手机.有一个开源的jar包能干这事儿:Android Screen Monitor(asm.jar),官网 https://code.google.com/p/android-screen-monitor/  . 1.到官网下载ASM的zip包,解压后得

Android进阶笔记21:Android手机屏幕坐标系

1. 手机屏幕坐标系: 整个坐标系是以手机屏幕左上角为原点(0,0),如下:

分享 Android 手机屏幕录制并制作成 GIF 演示图片

======================================================== 作者:qiujuer 博客:blog.csdn.net/qiujuer 网站:www.qiujuer.net 开源库:Genius-Android 转载请注明出处:http://blog.csdn.net/qiujuer/article/details/42506741 --学之开源,用于开源:初学者的心态,与君共勉! ================================