剑指Offer——面试题53:在排序数组中查找数字

题目一:数字在排序数组中出现的次数

题目:统计一个数字在排序数组中出现的次数。例如输入排序数组{1, 2, 3, 3, 3, 3, 4, 5}和数字3,由于3在这个数组中出现了4次,因此输出4。
#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
using namespace std;
int GetFirstK(int* data, int length, int k, int start, int end){  // 找到第一个k在数组中的下标, 不存在返回-1 
	if(start>end) return -1;
	int midIndex=(start+end)/2;
	int midData=data[midIndex];
	if(midData==k){
		if((midIndex>0 && data[midIndex-1]!=k) || midIndex==0){
			return midIndex;
		}else end=midIndex-1;
	} else if(midData>k) end=midIndex-1;
	else start=midIndex+1;
	
	return GetFirstK(data, length, k, start, end);
}
int GetLastK(int* data, int length, int k, int start, int end){  // 找到最后一个k在数组中的下标, 不存在返回-1 
	if(start>end) return -1;
	int midIndex=(start+end)/2;
	int midData=data[midIndex];
	if(midData==k){
		if((midIndex<length-1 && data[midIndex+1]!=k) || midIndex==length-1) return midIndex;
		else start=midIndex+1;
	}else if(midData>k) end=midIndex-1;
	else start=midIndex+1;
	
	return GetLastK(data, length, k, start, end);
}
int GetNumberOfK(int* data, int length, int k){
	int number=0;
	if(data!=NULL && length>0){
		int first=GetFirstK(data, length, k, 0, length-1);
		int last=GetLastK(data, length, k, 0, length-1);
		
		if(first>-1 && last>-1)
			number=last-first+1;
	}
	return number;
}
int main() {
	int data[]={1, 2, 3, 3, 3, 3, 4, 5};
	printf("%d", GetNumberOfK(data, 8, 3));
	return 0;
}

题目二:0~n-1 中缺失的数字。

题目:一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0到n-1之内。在范围0到n-1的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
解决思路:

方法一:这个问题有一个直观的解决方案。我们可以先用公式 n(n-1)/2 求出数字 0~n-1 的所有数字之后,接着求出数组中的所有数字的和,做差即可求出缺失值。时间复杂度O(n)
方法二:利用二分法查找,数字m和下标m对应。时间复杂度O(logn)

#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
using namespace std;
int GetMissingNumber(const int* numbers, int length){
	if(numbers==NULL || length<0) return -1;
	int left=0, right=length-1;
	while(left<=right){
		int mid=(left+right)>>1;
		if(numbers[mid]!=mid){  // 只要往左边查找 
			if(mid==0 || numbers[mid-1]==mid-1) return mid;
			right=mid-1;
		}else left=mid+1;  //  只要往右边查找 
	}	
	if(left==length) return length;
	
	// 无效的输入, 比如数组不是按要求排序的, 或者有数字不在 0~n-1 范围内
	return -1; 
}
	
int main() {
	int data[]={0, 1, 2, 3, 4, 6, 7, 8, 9 ,10}; 
	printf("%d", GetMissingNumber(data, 10));
	return 0;
}

题目三:数组中数值和下标相等的元素。

题目:假设一个单调递增的数组里的每个元素都是整数并且是唯一的。请编程实现一个函数找出数组中任意一个数值等于其下标的元素。例如,在数组{-3, -1, 1, 3, 5}中,数字3和它的下标相等。
解决思路:

方法一:我们很容易就能想到最直观的解法:从头到尾依次扫描数组中的数字,并逐一检验数字是不是和下标相等。显然,这种算法的时间复杂度是O(n)。
方法二:由于数组是单调递增排序的,因此我们可以尝试用二分查找算法来进行优化。

#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
using namespace std;
int GetNumberSameAsIndex(const int* numbers, int length){
	if(numbers==NULL || length<=0) return -1;
	int left=0, right=length-1;
	while(left<=right){
		int mid=(left+right)>>1;
		if(numbers[mid]==mid) return mid;
		else if(numbers[mid]>mid) right=mid-1;
		else left=mid+1;
	}
	return -1;
}
	
int main() {
	int data[]={-3, -1, 1, 3, 5};
	printf("%d", GetNumberSameAsIndex(data, 5));
	return 0;
}
发布了74 篇原创文章 · 获赞 76 · 访问量 4054

猜你喜欢

转载自blog.csdn.net/qq_35340189/article/details/104475564
今日推荐