题目描述
题目一:
统计一个数字在排序数组中出现的次数。
题解一:
暴力求解O(n)
题解二:
O(logn) 利用二分查找法的思想,找到目标数所在的第一个位置以及目标数所在的最后一个位置,次数=最后一个位置-第一个位置+1
步骤:
1)先拿数组中间的数字和目标数去比较,如果中间的数小于目标数,那么目标数只可能出现在数组的后半段;大于目标数只可能在数组的前半段;如果中间的数等于目标数,见步骤2)3)
2)找到目标数的第一个位置:如果等于目标数,先判断这个数字是不是第一个目标数,如果这个数字的前一个数不是目标数,那么这个数所在下标就是第一个位置,否则第一个位置在数组(除去中间之后数组)的前半段
3)找到目标数的最后一个位置:如果等于目标数,先判断这个数是不是最后一个目标数,如果这个数字的后一个数不是目标数,那么这个数所在下标就是最后一个位置,否则最后一个位置在数组(除去中间数之后的数组)的后半段
public class Solution {
public int GetNumberOfK(int [] array , int k) {
int length = array.length;
if(length == 0) return 0;
int firstK = getFirstK(array, k, 0, length-1);//找到目标数所在的第一个位置
int lastK = getLastK(array, k, 0, length-1);//找到目标数所在的最后一个位置
if(firstK != -1 && lastK != -1){
return lastK - firstK + 1;
}
return 0;
}
//递归写法
//找到目标数的第一个位置
private int getFirstK(int [] array , int k, int start, int end){
if(start > end) return -1;
int mid = (start + end) >> 1;
if(array[mid] > k){
return getFirstK(array, k, start, mid-1);
}else if (array[mid] < k){
return getFirstK(array, k, mid+1, end);
}else if(mid-1 >=0 && array[mid-1] == k){//中间数的前一个数和目标数相等
return getFirstK(array, k, start, mid-1);//继续查找前段数组
}else{
return mid;
}
}
//找到目标数的最后一个位置
private int getLastK(int[] array,int target,int start,int end){
if(start>end) return -1;
int mid=(start+end)>>1;
if(array[mid]>target){
return getLastK(array,target,start,mid-1);
}else if(array[mid]<target){
return getLastK(array,target,mid+1,end);
}else if(mid+1<=end&&array[mid+1]==target){
return getLastK(array,target,mid+1,end);
}else{
return mid;
}
}
}
题目二:
0~n-1中缺失的数字
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0到n-1之内。
在范围0到n-1的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
题解:
根据二分查找,这道题目给定的是递增数组,假设数组中第一个缺失的数是 xx,那么数组中的数如下所示;
--------------------------------------------------
二分区间left mid right
如果二分的位置在,红色部分,说明要查找的数在红色左边(可以包含红色);更新区间[left,mid]
如果二分的位置在黑色部分,说明查找的数在中间数的右边;更新区间[mid+1,right]
另外要注意特殊情况:当所有数都满足nums[i] == i时,表示缺失的数不在n-1的范围内,就是right的下一个数。
class Solution {
public int getMissingNumber(int[] nums) {
if(nums.length==0) return -1;
int left=0,right=nums.length-1;
int mid=(left+right)>>1;
while(left<right){
if(nums[mid]!=mid) right=mid+1;
else left=mid+1;
}
//特殊情况,整个序列都是蓝颜色
if(nums[right]==right) right++;
return right;
}
}
题目三:
数组中数值和下标相等的元素
假设一个单调递增的数组里的每个元素都是整数并且是唯一的。
请编程实现一个函数找出数组中任意一个数值等于其下标的元素。
例如,在数组[-3, -1, 1, 3, 5]中,数字3和它的下标相等。
题解:单调的数组利用二分查找的思路
步骤:
1)如果array[mid]==mid;那么这个值就是要找的数;
2)如果array[mid]>mid;说明数组右半边的数都大于下标的值;下一次要从数组的左半边查找,证明略
3)如果array[mid]<mid;说明数组左半边的数都小于下标的值;下一次要从数组的右半边查找;
class Solution {
public int getNumberSameAsIndex(int[] nums) {
if(nums.length==0) return -1;
int left=0,right=nums.length-1;
int mid=left+(right-left)>>1;//防止数组的下标溢出
while(left<=right){
if(mid==nums[mid]) return mid;
if(mid<nums[mid]){
//目标在左边
right=mid-1;
}else{
//目标在右边
left=mid+1;
}
}
return -1;
}
}