一,問題描述
假設給定一個有序的整型數組arr,以及一個整數 k,問 k在數組中出現了幾次?
二,求解思路
①數組是有序的,故可考慮用二分查找
②如果能找到 k 在數組中第一次出現時的索引位置first_index 和 最后一次出現時的索引位置last_index
就可以知道 k 出現的次數了: (last_index - first_index) + 1
而對於有序數組而言,可以通過二分查找求出某個數第一次出現的索引位置 和 最后一次出現的索引位置。故總的時間復雜度為O(logN)
③特殊情況考慮
k 不在數組中時怎么辦? 數組arr為null 或者 數組 arr.length == 0
核心思路:求解 k 第一次出現時的索引位置
首先找出arr[middle],如果 k 比中間元素大,則在右邊尋找k第一次出現時的索引位置(遞歸),若 k 比中間元素小,則在左邊尋找...(遞歸)。
若 k == arr[middle],則需要判斷 arr[middle -1] 是否等於 k,若不等於k,則說明 middle 就是 k 第一次出現時的索引;若等於 k,則繼續遞歸在左邊尋找,但是此時要注意 左邊索引不要越界(middle == low 了,就不能再往左邊尋找了)。
同理可求解,k 最后一次出現時的索引位置。
三,完整代碼實現
public class OccFreq { /** * 求解 k 在 arr 中第一次出現的索引位置 * @param arr 有序數組 * @param k * @return k第一次出現的索引位置,若 k 不在 arr中返回 -1 */ public static int getFirst(int[] arr, int k){ if(arr == null || arr.length == 0) throw new IllegalArgumentException("arr == null or arr.lenght == 0"); return getFirst(arr, 0, arr.length - 1, k); } private static int getFirst(int[] arr, int low, int high, int k){ int middle = (low + high) / 2; if(middle == low || middle == high) { if(arr[middle] == k) return middle; else // throw new IllegalArgumentException(k + " not in arr"); return -1; } if(arr[middle] > k) return getFirst(arr, low, middle - 1, k); else if(arr[middle] < k) return getFirst(arr, middle + 1, high, k); else { if(arr[middle - 1] == k) return getFirst(arr, low, middle - 1, k); else return middle; } } /** * 求解 k 在 arr 中最后一次出現的索引 * @param arr * @param k * @return k 在arr中的最后出現的索引, 若 k 不在 arr中返回 -1 */ public static int getLast(int[] arr, int k){ if(arr == null || arr.length == 0) throw new IllegalArgumentException("arr == null"); return getLast(arr, 0, arr.length - 1, k); } private static int getLast(int[] arr, int low, int high, int k){ int middle = (low + high) / 2; //已經尋找到最左邊 或 最右邊了. if(middle == low || middle == high) { if(arr[middle] == k) return middle; else // throw new IllegalArgumentException(k + " not in arr"); return -1;//k 不在 arr中 } if(arr[middle] > k){//繼續在左邊尋找 return getLast(arr, low, middle - 1, k); } else if(arr[middle] < k){//繼續在右邊尋找 return getLast(arr, middle + 1, high, k); } else//k== arr[middle] { if(arr[middle + 1] == k) return getLast(arr, middle + 1, high, k);//繼續在右邊尋找 else return middle; } } /** * 求解 k 在 arr數組中出現的次數 * @param arr 有序數組 * @param k * @return k 在 arr 數組中出現的次數 */ public static int freq(int[] arr, int k){ int first_index = getFirst(arr, k); int last_index = getLast(arr, k); if(first_index < 0 && last_index < 0) return 0; return last_index - first_index + 1; } public static void main(String[] args) { int[] arr = {2,4,5,6,8,8,8,9}; int freqs = freq(arr, 1); System.out.println(freqs); } }
