JZ37 数字在升序数组中出现的次数
给定一个长度为 n 的非降序数组和一个非负数整数 k ,要求统计 k 在数组中出现的次数
数据范围:1000≤n≤1000,0≤k≤100,数组中每个元素的值满足 1000≤val≤100
要求:空间复杂度 O(1)O(1),时间复杂度 O(logn)O(logn)
/* 第一反应for循环很简单,然后发现大家都是用二分法,于是艰难的看别人的二分法思路
*for循环方案
* 定义一个方法
* 返回值类型 int
* 入参1 数组 入参2元素
* */
public static int getNumFromArray(int[] array, int num) {
int sameNum = 0;
for (int j = 0; j < array.length; j++) {
int i = array[j];
if (num == i) {
sameNum += 1;
}
}
return sameNum;
}
/*
* 二分法解决方案
*[1,2,3,3,3,3,4,5],3 输出4
* */
public static int getNumberOfK(int[] array, int k) {
if (array == null || array.length == 0) {
// 判断数组元素个数
return 0;
}
int min = lowerBound(array, k);
int max = higherBound(array, k);
return max - min + 1;
}
// 计算左边
public static int lowerBound(int[] array, int target) {
int left = 0;
int right = array.length;
while (left < right) {
/* 从左到右找到第一个和target相同的元素下标
* [1,2,3,3,3,3,4,5]
* 二分法思路
* 第一次
* left = 0, right = 8, middle = 4
* array[left] = array[0] = 1
* array[middle] = array[4] = 3
* array[middle] = target = 3
* right = middle = 4
* 第二次
* left = 0, right = 4, middle = left + (right - left) / 2 = 2
* array[middle] = array[2] = 3
* array[middle] = target = 3
* right = middle = 2
* 第三次
* left = 0, right = 2, middle = left + (right - left) / 2 = 1
* array[middle] = array[1] = 2
* array[middle] < target
* left = middle + 1 = 2
* 第四次
* left == right == 2 跳出循环
* left == 2
* */
int middle = left + (right - left) / 2;
if (array[middle] == target) {
right = middle;
} else if (array[middle] > target) {
right = middle;
} else {
// array[middle] < target
left = middle + 1;
}
}
return left;
}
// 计算右边
public static int higherBound(int[] array, int target) {
int left = 0;
int right = array.length;
while (left < right) {
/* 从左到右找到最后一个和target相同的元素下标
* [1,2,3,3,3,3,4,5] target = 3 下标2,3,4,5的元素为3
* 第一次循环
* middle = 4
* (array[middle] = array[4] = 3) == target
* left = middle + 1 = 5
* 第二次循环
* left = 5, right = 8
* middle = left + (right - left) / 2 = 6
* array[middle] = array[6] = 4 > target
* right = middle = 6
* 第三次循环
* left = 5, right = 6
* middle = left + (right - left) / 2 = 5
* array[middle] = array[5] = 3 == target
* left = middle + 1 = 6
* 第四次循环
* left = 6, right = 6
* left = right = 6 跳出循环
* array[middle] = array[5] = 3 == target
* */
int middle = left + (right - left) / 2;
if (array[middle] == target) {
left = middle + 1;
} else if (array[middle] > target) {
right = middle;
} else {
// array[middle] < target
left = middle + 1;
}
}
return left - 1;
}