1. 程式人生 > >【劍指Offer學習】【面試題38:數字在排序陣列中出現的次數】

【劍指Offer學習】【面試題38:數字在排序陣列中出現的次數】

題目:統計一個數字:在排序陣列中出現的次數。

舉例說明

例如輸入排序陣列{ 1, 2, 3, 3, 3, 3, 4, 5}和數字3 ,由於3 在這個陣列中出現了4 次,因此輸出4 。

解題思路

  利用改進的二分演算法。
  如何用二分查詢演算法在陣列中找到第一個k,二分查詢演算法總是先拿陣列中間的數字和k作比較。如果中間的數字比k大,那麼k只有可能出現在陣列的前半段,下一輪我們只在陣列的前半段查詢就可以了。如果中間的數字比k小,那麼k只有可能出現在陣列的後半段,下一輪我們只在陣列的後半乓查詢就可以了。如果中間的數字和k 相等呢?我們先判斷這個數字是不是第一個k。如果位於中間數字的前面一個數字不是k,此時中間的數字剛好就是第一個k。如果中間數字的前面一個數字也是k,也就是說第一個k肯定在陣列的前半段, 下一輪我們仍然需要在陣列的前半段查詢。
  同樣的思路在排序陣列中找到最後一個k。如果中間數字比k大,那麼k只能出現在陣列的前半段。如果中間數字比k小,k就只能出現在陣列的後半段。如果中間數字等於k呢?我們需要判斷這個k是不是最後一個k,也就是中間數字的下一個數字是不是也等於k。如果下一個數字不是k,則中間數字就是最後一個k了:否則下一輪我們還是要在陣列的後半段中去查詢。

程式碼實現

public class Test38 {
    /**
     * 找排序陣列中k第一次出現的位置
     *
     * @param data
     * @param k
     * @param start
     * @param end
     * @return
     */
    private static int getFirstK(int[] data, int k, int start, int end) {
        if (data == null || data.length < 1 || start > end) {
            return
-1; } int midIdx = start + (end - start) / 2; int midData = data[midIdx]; if (midData == k) { if (midIdx > 0 && data[midIdx - 1] != k || midIdx == 0) { return midIdx; } else { end = midIdx - 1; } } else
if (midData > k) { end = midIdx - 1; } else { start = midIdx + 1; } return getFirstK(data, k, start, end); } /** * 找排序陣列中k最後一次出現的位置 * * @param data * @param k * @param start * @param end * @return */ private static int getLastK(int[] data, int k, int start, int end) { if (data == null || data.length < 1 || start > end) { return -1; } int midIdx = start + (end - start) / 2; int midData = data[midIdx]; if (midData == k) { if (midIdx + 1 < data.length && data[midIdx + 1] != k || midIdx == data.length - 1) { return midIdx; } else { start = midIdx + 1; } } else if (midData < k) { start = midIdx + 1; } else { end = midIdx - 1; } return getLastK(data, k, start, end); } /** * 題目:統計一個數字:在排序陣列中出現的次數 * @param data * @param k * @return */ public static int getNumberOfK(int[] data, int k) { int number = 0; if (data != null && data.length > 0) { int first = getFirstK(data, k, 0, data.length - 1); int last = getLastK(data, k, 0, data.length - 1); if (first > -1 && last > -1) { number = last - first + 1; } } return number; } public static void main(String[] args) { // 查詢的數字出現在陣列的中間 int[] data1 = {1, 2, 3, 3, 3, 3, 4, 5}; System.out.println(getNumberOfK(data1, 3)); // 4 // 查詢的陣列出現在陣列的開頭 int[] data2 = {3, 3, 3, 3, 4, 5}; System.out.println(getNumberOfK(data2, 3)); // 4 // 查詢的陣列出現在陣列的結尾 int[] data3 = {1, 2, 3, 3, 3, 3}; System.out.println(getNumberOfK(data3, 3)); // 4 // 查詢的數字不存在 int[] data4 = {1, 3, 3, 3, 3, 4, 5}; System.out.println(getNumberOfK(data4, 2)); // 0 // 查詢的數字比第一個數字還小,不存在 int[] data5 = {1, 3, 3, 3, 3, 4, 5}; System.out.println(getNumberOfK(data5, 0)); // 0 // 查詢的數字比最後一個數字還大,不存在 int[] data6 = {1, 3, 3, 3, 3, 4, 5}; System.out.println(getNumberOfK(data6, 0)); // 0 // 陣列中的數字從頭到尾都是查詢的數字 int[] data7 = {3, 3, 3, 3}; System.out.println(getNumberOfK(data7, 3)); // 4 // 陣列中的數字從頭到尾只有一個重複的數字,不是查詢的數字 int[] data8 = {3, 3, 3, 3}; System.out.println(getNumberOfK(data8, 4)); // 0 // 陣列中只有一個數字,是查詢的數字 int[] data9 = {3}; System.out.println(getNumberOfK(data9, 3)); // 1 // 陣列中只有一個數字,不是查詢的數字 int[] data10 = {3}; System.out.println(getNumberOfK(data10, 4)); // 0 } }

執行結果

這裡寫圖片描述