找出数字在已排序数组中出现的次数

一,问题描述

假设给定一个有序的整型数组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);
    }
}
时间: 2024-10-28 14:15:44

找出数字在已排序数组中出现的次数的相关文章

【剑指Offer学习】【面试题38:数字在排序数组中出现的次数】

题目:统计一个数字:在排序数组中出现的次数. 举例说明 例如输入排序数组{ 1, 2, 3, 3, 3, 3, 4, 5}和数字3 ,由于3 在这个数组中出现了4 次,因此输出4 . 解题思路 利用改进的二分算法. 如何用二分查找算法在数组中找到第一个k,二分查找算法总是先拿数组中间的数字和k作比较.如果中间的数字比k大,那么k只有可能出现在数组的前半段,下一轮我们只在数组的前半段查找就可以了.如果中间的数字比k小,那么k只有可能出现在数组的后半段,下一轮我们只在数组的后半乓查找就可以了.如果中

剑指offer-第六章面试中的各项能力(数字在排序数组中出现的次数)

题目:统计一个数字在排序数组中出现的次数. 思路:采用二分查找,找到该数字在数组中第一次出现的位置,然后再找到组后一个出现的位置.两者做减法运算再加1. Java代码: //数字K在排序数组中出现的次数 //思路:用二分查找,找到第一个k和最后一个K public class NumberCount { public int numberCount(int[] a,int k){ if(a==null) return 0; int start=0; int end=a.length-1; int

剑指offer——面试题38:数字在排序数组中出现的次数(利用二分查找来找第一次和最后一次的位置)

题目: 统计一个数字在排序数组中出现的次数. 思路: 因为是排好序的数组,所以可以采用二分查找的算法. 一般最容易想到的思路是采用二分查找先找到一个,然后往他左右两边遍历,但是这个方法由于在n个数组中还可能有n个k,所以 查找的复杂度还是O(n) 可以先用二分查找算法找到第一个出现的位置,即当找到一个时,看它前面一个是否也是k或者是否已经是查找这段的第一个了 然后同样用二分查找找最后一个出现的位置. 1 #include<iostream> 2 #include<vector> 3

剑指offer 面试题38—数字在排序数组中出现的次数

题目: 统计一个数字在排序数组中出现的次数.例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4. 解法一:O(n) 顺序遍历 解法二:O(logn) 用二分查找,分别找出第一个3,和最后一个3的位置,然后计算个数. #include <stdio.h> int GetFirstK(int* data,int length,int k,int start,int end) { if(start > end) return -1; int m

《剑指offer》:[38]数字在排序数组中出现的次数

"沟通.学习能力就是看面试者能否清晰.有条理地表达自己,是否会在自己所得到的信息不够的情况下主动发问澄清,能否在得到一些暗示之后迅速做出反应纠正错误"                                                                                                                   ---陈黎明(MSoft-SDE) 题目:统计一个数字在排序数组中出现的次数.例如输入排序数组{1,2,3,3

(剑指Offer)面试题38:数字在排序数组中出现的次数

题目: 统计一个数字在排序数组中出现的次数. 思路: 1.顺序遍历 顺序扫描一遍数组,统计该数字出现的次数. 时间复杂度:O(n) 2.二分查找 假设我们需要找的数字是k,那么就需要找到数组中的第一个k和最后一个k出现的位置. 如何通过二分查找得到第一个k的位置呢? 取数组中间的数字与k作比较, 如果该数字比k大,那么k只能出现在前半部分,那么下一轮只能在前半部分找: 如果该数字比k小,那么k只能出现在后半部分,那么下一轮只能在后半部分找: 如果该数字等于k,需要判断这是不是第一个k,如果该数字

【剑指offer】面试题38:数字在排序数组中出现的次数

题目: 统计一个数字在排序数组中出现的次数. 思路: 对二分查找进行改进,找到数字在数组中第一次出现和最后一次出现的位置,这样就得到它出现的次数. 以找第一次出现的位置为例:如果mid元素大于k,则在前半段找:如果小于k,则在后半段找:如果等于k,则要看mid的前一个元素是不是k,如果是,则在前半段找,如果不是,则这就是第一次出现的位置. 时间复杂度O(logn). 代码: class Solution { public: int GetNumberOfK(vector<int> data ,

数字在排序数组中出现的次数-剑指Offer

数字在排序数组中出现的次数 题目描述 统计一个数字在排序数组中出现的次数. 思路 处理已排好序的数组,考虑用二分查找的思想 用二分查找找到这个数出现的第一个位置,再找到出现的最后一个位置,可得这个数出现几次,这样的时间复杂度为O(logn) 注意考虑数组中没有出现该数的情况 代码 public class Solution { public int GetNumberOfK(int [] array , int k) { int num = 0; if (array == null || arr

统计数字在排序数组中出现的次数

统计一个数字在排序数组中出现的次数: 可定义一个用于统计数字个数的变量count,然后从前往后遍历数组,看是否与所求数字相等,如果相等,则count++: 下面贴出代码: public class Solution {     public int GetNumberOfK(int [] array , int k) {         int count = 0;        for(int i=0;i<array.length;i++){            if(array[i]==k