【刷題】Search in a Big Sorted Array

monkeysayhi發表於2019-01-04

原題戳我

題目

Description

Given a big sorted array with positive integers sorted by ascending order. The array is so big so that you can not get the length of the whole array directly, and you can only access the kth number by ArrayReader.get(k) (or ArrayReader->get(k) for C++). Find the first index of a target number. Your algorithm should be in O(log k), where k is the first index of the target number.

Return -1, if the number doesn`t exist in the array.

Notice:
If you accessed an inaccessible index (outside of the array), ArrayReader.get will return 2147483647.

Example

  • Given [1, 3, 6, 9, 21, …], and target = 3, return 1.
  • Given [1, 3, 6, 9, 21, …], and target = 4, return -1.

Challenge

O(log k), k is the first index of the given target number.

Tags

Sorted Array Binary Search

分析

這道題我是看題解才做出來的,思路非常好,有兩個重點:

  1. 可以O(logk)的時間縮小二分法的範圍
  2. 從而,可以將二分的最壞時間優化到O(logk)

第二點無需證明,下面講解第一點。

以O(logk)的時間縮小二分法的範圍

如果從0遍歷到k,那麼明顯時間複雜度為O(k),超過了了O(logk)。

要記得,我們的目的是確定一個陣列的上界r,使O(r)=O(k),繼而在這段陣列上進行二分查詢,複雜度為O(logk)。因此,我們只需要將在O(logk)的時間內找到該r。

r的要求如下:

  1. 滿足O(r)=O(k)
  2. 計算r的時間為O(logk)

即,尋找一個運算,進行O(logk)次,結果為O(k)。於是想到了乘冪

2 ** O(logk) = O(k)複製程式碼

程式碼如下:

    private int[] computeRange(ArrayReader reader, int target){
        int r = 1;
        while (reader.get(r) < target) {
            r <<= 1;
        }

        int l = r >> 1;
        while (r >= l && reader.get(r) == 2147483647) {
            r--;
        }
        if (r < l) {
            return null;
        }

        return new int[]{l, r};
    }複製程式碼

完整程式碼

/**
 * Definition of ArrayReader:
 * 
 * class ArrayReader {
 *      // get the number at index, return -1 if index is less than zero.
 *      public int get(int index);
 * }
 */
public class Solution {
    /**
     * @param reader: An instance of ArrayReader.
     * @param target: An integer
     * @return : An integer which is the index of the target number
     */
    public int searchBigSortedArray(ArrayReader reader, int target) {
        // write your code here
        if (reader == null) {
            return -1;
        }

        if (reader.get(0) > target) {
            return -1;
        }

        int[] range = computeRange(reader, target);
        if (range == null) {
            return -1;
        }

        int k = bsearchLowerBound(reader, range[0], range[1], target);
        if (reader.get(k) != target) {
            return -1;
        }

        return k;
    }

    private int[] computeRange(ArrayReader reader, int target){
        int r = 1;
        while (reader.get(r) < target) {
            r <<= 1;
        }

        int l = r >> 1;
        while (r >= l && reader.get(r) == 2147483647) {
            r--;
        }
        if (r < l) {
            return null;
        }

        return new int[]{l, r};
    }

    private int bsearchLowerBound(ArrayReader reader, int l, int r, int v) {
        while (l < r) {
            int m = l + (r - l) / 2;
            if (reader.get(m) >= v) {
                r = m;
            } else {
                l = m + 1;
            }
        }
        return l;
    }
}複製程式碼

本文連結:【刷題】Search in a Big Sorted Array
作者:猴子007
出處:monkeysayhi.github.io
本文基於 知識共享署名-相同方式共享 4.0 國際許可協議釋出,歡迎轉載,演繹或用於商業目的,但是必須保留本文的署名及連結。

相關文章