面试题目53:在排序数组中查找数字

题目描述

题目一:

       统计一个数字在排序数组中出现的次数。

题解一

      暴力求解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;
    }
}

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值