1. 程式人生 > >Leetcode刷題系列(二)Binary Search

Leetcode刷題系列(二)Binary Search

Binary Search的基礎框架程式碼

Bianry Search的基本思想

  二分查詢法是基於一組有序數上的查詢,它的時間複雜度最壞為O(n),平均時間複雜度為O(lgn),空間複雜度為O(1)。由於它不需要藉助額外的空間,並且大多數情況下(平均)效能較好,所以是應用較廣的一種查詢法。
  接下來介紹一些其他查詢方法的時間和空間複雜度:

查詢演算法 平均時間複雜度 最壞時間複雜度 空間複雜度
順序查詢 O(n) O(n) O(1)
二分查詢 O(lgn) O(n) O(1)
二叉樹查詢 O(lgn) O(lgn) O(n)
雜湊查詢 O(1) O(1) O(n)

  二叉樹查詢需要在原有資料的基礎上建立二叉排序樹,因此需要額外的空間,比較適合多次連續查詢。類似的演算法有雜湊查詢,需要額外空間建立雜湊表,同時考慮衝突處理等問題。
  可以看出,二叉查詢是比較適合不知道查詢次數的情況。因為他不需要建立額外儲存結構。

Bianry Search的基礎框架程式碼

  該程式碼為實現在有序陣列中查詢某個目標數的基本框架,與二叉查詢有關的其他題型可在此框架上進行修改。
  

    public int findPosition(int[] nums, int
target) { if (nums == null || nums.length == 0) { return -1; } int start = 0, end = nums.length - 1; while (start + 1 < end) { int mid = start + (end - start) / 2; if (nums[mid] == target) { return mid; } else
if (nums[mid] < target) { start = mid; } else { end = mid; } } if (nums[start] == target) { return start; } if (nums[end] == target) { return end; } return -1; }

  該程式碼搜尋位置比較偏左,搜尋到的目標數可能的第一個位置為start。

Binary Search的相關題型

Search Insert Position

  題目為搜尋目標數第一個出現的位置,如果找不到則返回其應該插入的位置。

  換種思路可以有:搜尋源數組裡第一個大於等於目標數的位置,或者最後一個小於目標數的位置+1。這兩種思想需要充分利用start和end的位置關係。

Search a 2D Matrix I

  題目為在一個二維陣列中搜索目標數。

  解題思路有以下兩種:

  • 由於二維數組裡的數是嚴格遞增的,因此可以將二維陣列看成一維陣列進行搜尋,每個數的下標可以看成是i×n+j。使用matrix[mid / column][mid % column]與目標數進行對比。
  • 可以先搜尋行,再搜尋列。注意搜尋行的時候,去尋找第一個小於等於matrix[mid][0]的數,該數所在的行數即為所要找的行數。因此,退出迴圈之後要先與matrix[end][0]進行對比。

Search a 2D Matrix II

  題目為寫出一個高效的演算法來搜尋m×n矩陣中的值,返回這個值出現的次數。這個矩陣具有以下特性:

  • 每行中的整數從左到右是排序的。
  • 每一列的整數從上到下是排序的。
  • 在每一行或每一列中沒有重複的整數。

      該二維陣列中的數並不是嚴格遞增的,因此不適合上題中的方法。但其可以看成是是在二維座標軸中進行向右或向上的行走。即初始時在左下角逐漸向右上角進行搜尋。程式碼片段:

     while (x >= 0 && y < m) {
            if (matrix[x][y] < target) {
                y++;
            } else if (matrix[x][y] > target) {
                x--;
            } else {
                count++;
                x--;
                y++;
            }
        }

Find Peak Element

  題目為返回任意一個峰值的位置。因此,應使A[mid]與A[mid + 1]和A[mid - 1]進行比較,最後的結果在A[start]和A[end]之間,所以還需要進行最後一次判斷,返回較大者。

First Bad Version

  該題需要返回第一個錯誤的版本,要求呼叫次數較少。呼叫次數可以看成比較次數,某種意義上說也是時間複雜度,因此使用二分查詢很合適。使用上述框架,則可以考慮成尋找第一個位置上的SVNRepo.isBadVersion(mid)為ture的值。