【劍指Offer學習】【面試題38:數字在排序陣列中出現的次數】
阿新 • • 發佈:2019-01-07
題目:統計一個數字:在排序陣列中出現的次數。
舉例說明
例如輸入排序陣列{ 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
}
}