劍指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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章