找出數字在已排序數組中出現的次數


一,問題描述

假設給定一個有序的整型數組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);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM