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

题目描述

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

思路(剑指offer书上)

o(n)的很容易想到

 public class Solution {
        public int GetNumberOfK(int[] array, int k) {
        int num = 0;
        for (int i = 0; i < array.length; i++) {
            if (array[i] == k)
                num++;
        }
        return num;
    }
 }

可以用二分实现o(logn)

  1. 查找第一个k:
  • 中间数字等于k,看中间数字的前一个是不是k,前一个是k,说明第一个k在前半段,如果前一个数字不是k,说明中间数组的这个k是第一个k;
  • 数值大于k,说明第一个k在前半部分;
  • 中间数值小于k,说明第一个k在后半部分。
  1. 查找最后一个k:
  • 中间数字等于k,看中间数字的后一个是不是k,后一个是k,说明最后一个k在后半段,如果后一个数字不是k,说明中间数组的这个k是最后一个k;
  • 中间数值大于k,说明最后一个k在前半部分;
  • 中间数值小于k,说明最后一个k在后半部分。
  1. 查找第一个k与最后一个k,两个位置之间有多少个即为长度。

java实现

public class Solution {
    public static int GetNumberOfK(int[] array, int k) {
        int num = 0;
        int length = array.length;
        if (array == null && length == 0) 
            return num;
        int first = GetFirstK(array, k, 0, length - 1);//得到第一个k的位置
        int last = GetLastK(array, k, 0, length - 1);//得到最后一个k的位置
        if (first > -1 && last > -1)
            num = last - first + 1;
        return num;
    }

    static int GetFirstK(int[] array, int k, int start, int end) {
        if (start > end)
            return -1;
        int mid = (start + end) / 2;
        if (array[mid] == k) {
            //中间数组是k,看中间数字的前一个是不是k,
            //前一个是k,说明第一个k在前半段,如果前一个数字不是k,说明中间数组的这个k是第一个k
            if (mid >= 1 && array[mid - 1] != k || mid == 0)
                return mid;
            else
                end = mid - 1;
        } else if (array[mid] > k)//中间数值大于k,说明第一个k在前半部分
            end = mid - 1;
        else//中间数值小于k,说明第一个k在后半部分
            start = mid + 1;
        return GetFirstK(array, k, start, end);

    }

    static int GetLastK(int[] array, int k, int start, int end) {
        if (start > end)
            return -1;
        int mid = (start + end) / 2;
        if (array[mid] == k) {
            //中间数组是k,看中间数字的后一个是不是k,
            //后一个是k,说明最后一个k在后半段,如果后一个数字不是k,说明中间数组的这个k是最后一个k
            if (mid+1 <= array.length-1 && array[mid + 1] != k || mid == array.length - 1)
                return mid;
            else
                start = mid + 1;
        } else if (array[mid] > k)//中间数值大于k,说明最后一个k在前半部分
            end = mid - 1;
        else//中间数值小于k,说明最后一个k在后半部分
            start = mid + 1;
        return GetLastK(array, k, start, end);
    }
}

你可能感兴趣的:(剑指offer)