题目一:数字在排序数组中出现的次数
统计一个数字在排序数组中出现的次数。
例子:
如,输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4。
链接:
剑指Offer(第2版):P263
思路标签:
- 算法:二分查找
- 数组排序好,第一个3和最后一个3决定
解答:
时间复杂度O(logn)的解法
- 在排序中的数组做查找,很自然可以想到使用二分查找法;
- 因为数组的个数只取决于第一个和最后一个的位置,所以我们只需要寻找第一个和最后一个该数字的位置即可;
- 应用二分查找,如果当前的中间数是该数字k,那么要么这个数字就是中间数字,要么就是第一或者最后一个数字;
- 以查找第一个k为例:
- 如果中间数字即为k:如果前面一个数字不是k,那么这个k即为第一个;如果前面一个数字也是k,那么第一个k就在数组的前半部分,继续查找。
- 如果中间数字不为k,大于k则在前半部分查找,小于k则在后半部分查找。
class Solution {
public:
int GetNumberOfK(vector<int> data, int k) {
int number = 0;
int length = data.size();
if (length > 0) {
int first = GetFirstK(data, k, 0, length - 1);
int last = GetLastK(data, k, 0, length - 1);
if (first > -1 && last > -1)
number = last - first + 1;
}
return number;
}
int GetFirstK(vector<int> &data, int k, int start, int end) {
int length = data.size();
if (start > end)
return -1;
int middleIndex = (start + end) / 2;
int middleData = data[middleIndex];
if (middleData == k) {
if ((middleIndex > 0 && data[middleIndex - 1] != k) || middleIndex == 0)
return middleIndex;
else
end = middleIndex - 1;
}
else if (middleData > k)
end = middleIndex - 1;
else
start = middleIndex + 1;
return GetFirstK(data, k, start, end);
}
int GetLastK(vector<int> &data, int k, int start, int end) {
int length = data.size();
if (start > end)
return -1;
int middleIndex = (start + end) / 2;
int middleData = data[middleIndex];
if (middleData == k) {
if ((middleIndex < length - 1 && data[middleIndex + 1] != k) || middleIndex == length - 1)
return middleIndex;
else
start = middleIndex + 1;
}
else if (middleData < k)
start = middleIndex + 1;
else
end = middleIndex - 1;
return GetLastK(data, k, start, end);
}
};
题目二:0~n-1中缺失的数字
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不再该数组中,请找出这个数字。
链接:
剑指Offer(第2版):P266
LeetCode-268:Missing Number(寻找缺失数字)
思路标签:
- 算法:二分查找
解答:
时间复杂度O(logn)的解法
- 一种比较直观的解法就是利用公式n(n-1)/2对0~n-1求和记为s1,再求数组中所有数字和,记为s2,s1-s2的结果就是确实的数字。时间复杂度O(n),没有利用数组排序的性质。
- 转换问题,因为是排序数组,数组中前面的数字和其下标是相同的,从缺失数字开始,后面的数字和其下标不相同。
- 利用上面的性质,使用二分查找:寻找在排序数组中第一个值和下标不相等的下标。
class Solution {
public:
int GetMissingNumber(const int* numbers, int length) {
if (numbers == nullptr || length < 0)
return -1;
int start = 0;
int end = length - 1;
while (start <= end) {
int middle = (start + end) >> 1;
if (numbers[middle] != middle) {
if (middle == 0 || numbers[middle - 1] == middle - 1)
return middle;
end = middle - 1;
}
else
start = middle + 1;
}
if (start == length)
return length;
}
};