算法筆試利器--對數器的使用

對數器的做用

對數器是經過用大量測試數據來驗證算法是否正確的一種方式。在算法筆試的時候,咱們常常只能肯定咱們寫出的算法在邏輯上是大體正確的,可是誰也不能一次性保證絕對的正確。特別是對於一些複雜的題目,例如貪心算法,咱們每每沒法在有限時間內用數學公式來推導證實咱們程序的正確性。並且在線的OJ通常只會給出有數的幾個簡單的samples,可能咱們的算法在這些簡單的samples偶然經過了,可是在一些複雜的samples處卻出現了問題。這時咱們沒法使用複雜的samples來分析調試咱們的代碼,人工設計樣例來測試代碼的效率又過低,並且不能確保考慮各類特殊狀況。所以,能隨機產生不一樣狀況的數據的對數器就派上了用場。java

對數器,簡而言之,就是一個絕對正確的方法和能產生大量隨機樣例的隨機器的組合。看到這裏,有些童鞋有疑問了。既然咱們知道了絕對正確的方法,直接用這個方法不就行了嘛?python

請注意,算法追求的不是解決問題,而是高效率的解決問題。對於一個數組的排序,若是筆試中要求的時間複雜度是$O(NlogN)$$,可是你卻寫了一個冒泡排序的算法交上去了,這時OJ就會提示:git

Time Limit Exceeded

而在對數器中,咱們要求的絕對正確的算法是沒有時間和空間複雜度的限制的,惟一的要求是確保絕對正確。由於只有絕對正確,咱們才能經過樣例的比對,發現咱們的代碼是在哪裏出了錯誤。github

相關概念

  1. 有一個你想要測的方法a
  2. 實現一個絕對正確可是複雜度很差的方法b
  3. 實現一個隨機樣本產生器;
  4. 實現對比算法ab的方法;
  5. 把方法a和方法b比對屢次來驗證方法a是否正確;
  6. 若是有一個樣本使得比對出錯,打印樣本分析是哪一個方法出錯;
  7. 當樣本數量不少時比對測試依然正確,能夠肯定方法a已經正確。

其中要注意如下幾點:算法

  • 隨機產生的樣本應該是小數據集,可是要進行屢次(10w+)的對比。小數據集是由於方便對比分析,屢次比對是要覆蓋全部的隨機狀況。
  • 算法b要保持正確性。

示例

冒泡排序的對數器:數組

  1. 要測的方法dom

    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都是留給有準備的人~~

數組排序

後續版本,陸續更新中.....

相關文章
相關標籤/搜索