算法笔试利器--对数器的使用

35岁倒计时
• 阅读 10643

对数器的作用

对数器是通过用大量测试数据来验证算法是否正确的一种方式。在算法笔试的时候,我们经常只能确定我们写出的算法在逻辑上是大致正确的,但是谁也不能一次性保证绝对的正确。特别是对于一些复杂的题目,例如贪心算法,我们往往无法在有限时间内用数学公式来推导证明我们程序的正确性。而且在线的OJ一般只会给出有数的几个简单的samples,可能我们的算法在这些简单的samples偶然通过了,但是在一些复杂的samples处却出现了问题。这时我们无法使用复杂的samples来分析调试我们的代码,人工设计样例来测试代码的效率又太低,而且不能确保考虑各种特殊情况。因此,能随机产生不同情况的数据的对数器就派上了用场。

对数器,简而言之,就是一个绝对正确的方法和能产生大量随机样例的随机器的组合。看到这里,有些童鞋有疑问了。既然我们知道了绝对正确的方法,直接用这个方法不就好了嘛?

请注意,算法追求的不是解决问题,而是高效率的解决问题。对于一个数组的排序,如果笔试中要求的时间复杂度是$O(NlogN)$$,但是你却写了一个冒泡排序的算法交上去了,这时OJ就会提示:

Time Limit Exceeded

而在对数器中,我们要求的绝对正确的算法是没有时间和空间复杂度的限制的,唯一的要求是确保绝对正确。因为只有绝对正确,我们才能通过样例的比对,发现我们的代码是在哪里出了错误。

相关概念

  1. 有一个你想要测的方法a
  2. 实现一个绝对正确但是复杂度不好的方法b
  3. 实现一个随机样本产生器;
  4. 实现对比算法ab的方法;
  5. 把方法a和方法b比对多次来验证方法a是否正确;
  6. 如果有一个样本使得比对出错,打印样本分析是哪个方法出错;
  7. 当样本数量很多时比对测试依然正确,可以确定方法a已经正确。

其中要注意以下几点:

  • 随机产生的样本应该是小数据集,但是要进行多次(10w+)的对比。小数据集是因为方便对比分析,多次比对是要覆盖所有的随机情况。
  • 算法b要保持正确性。

示例

冒泡排序的对数器:

  1. 要测的方法

    public static void bubbleSort(int[] arr)
    {
        if (arr==null || arr.length < 2)
            return;
        for (int end = arr.length - 1;end>0; end--)
        {
            for (int i = 0; i < end; i++)
            {
                if (arr[i] > arr[i+1])
                    swap(arr, i, i+1);
            }
        }
    }
  2. 实现一个绝对正确,可以复杂度不是很好的方法b

    // 可以直接用一些库函数来进行测试
    public static void rightMethod(int[] arr)
    {
        Arrays.sort(arr);
    }
  3. 实现一个随机样本产生器

    // 随机数生成器
    public static int[] generateRandomArray(int size, int value)
    {
    //Math.random() -> double [0,1)
    //(int) ((size + 1) * Math.random()) -> [0,size]整数
    // 生成长度随机[0, size]的数组
    int[] arr = new int[(int) ((size+1) * Math.random())];
    for (int i = 0; i < arr.length; i++)
    {
        // 一个随机数减去另一个随机数,生成[-value, value]的随机数
        arr[i] = (int) ((value+1) * Math.random()) - (int) (value * Math.random());
    }
    return arr;
    }
  4. 实现比对的方法

    // 判断两个数组是否相等
    public static boolean isEqual(int[] arr1, int[] arr2)
    {
        if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null))
            return false;
        if (arr1 == null && arr2 == null)
            return true;
        if (arr1.length != arr2.length)
            return  false;
        for (int i = 0; i < arr1.length; i++)
        {
            if (arr1[i] != arr2[i])
                return false;
        }
        return true;
    }
  5. 将方法a和方法b进行多次的比对
  6. 如果有一个样本使得本次比对出错,则打印该样本,分析方法错在哪里
  7. 当样本数量足够多时,比对测试依然正确,则可以确定我们写的方法a是正确的

    public static void main(String[] args) 
    {
        int testTime = 500000;
        int size = 10;
        int value = 100;
        boolean succeed = true;
        for (int i = 0; i < testTime; i++)
        {
            int[] arr1 = generateRandomArray(size, value);
            int[] arr2 = copyArray(arr1);
            int[] arr3 = copyArray(arr1);
            bubbleSort(arr1);
            rightMethod(arr2);
            if (!isEqual(arr1, arr2))
            {
                succeed = false;
                printArray(arr3);
                break;
            }
        }
        System.out.println(succeed ? "Nice!" : "error----");
        int[] arr = generateRandomArray(size, value);
        printArray(arr);
        bubbleSort(arr);
        printArray(arr);
    
    }

小提示

很多童鞋进行笔试前,都是背一些记在小本本上的代码,然后匆匆上阵。写出的算法的正确性完全靠OJ的判断,当程序卡在一个2000行的数组样例处出现错误时,就完全傻了......这T喵叫我怎么去进行调试分析啊。而有对数器的小伙伴就不一样了,由于使用的都是小样本,出现错误时也方面进行分析。而且进行了多次测试,确保覆盖了所有的特殊情况。因此笔试前我们可以准备一些对数器模版,如数组排序的对数器,链表的对数器等等。后续我也会更新一些对数器的模版,有java版本和python版本。

记住哦,offer都是留给有准备的人~~

数组排序

后续版本,陆续更新中.....

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
代码还原的技术: Unidbg hook_add_new实现条件断点(二)
一、目标在做代码还原的时候,有时候会分析一组结果,希望在中途下个条件断点,比如在代码行0x1234,R00x5678的时候触发断点。今天我们就来试着搞一下。TIP:Unidbg代码同步到官方最新版,最新版已经支持浮点寄存器的显示了。二、步骤先写个floatdemotwo把祖传算法升个级extern"C"JNIEXPORTjstringJNIC
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
菜园前端 菜园前端
2年前
什么是时间复杂度?
原文链接:什么是时间复杂度?定性描述该算法的运行时间,一个函数、用大O表示,例如O(1)、O(n)、O(logN)...常见的时间复杂度量级常数阶O(1)对数阶O(logN)线性阶O(n)线性对数阶O(nlogN)平方阶O(n²)立方阶O(n)K次方阶O(
拆解雪花算法生成规则 | 京东物流技术团队
雪花算法(Snowflake)是一种生成分布式全局唯一ID的算法,生成的ID称为SnowflakeIDs或snowflakes。这种算法由Twitter创建,并用于推文的ID。目前仓储平台生成ID是用的雪花算法修改后的版本。
分布式系统的主键生成方案对比 | 京东云技术团队
UUID​UUID(通用唯一识别码)是由32个十六进制数组成的无序字符串,通过一定的算法计算出来。为了保证其唯一性,UUID规范定义了包括网卡MAC地址、时间戳、名字空间(Namespace)、随机或伪随机数、时序等元素,以及从这些元素生成UUID的算法。