• 剑指Offer对答如流系列


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

    题目描述

    问题(1) 数字在排序数组中出现的次数

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

    例如输入排序数组{1, 2, 3, 3,3, 3, 4, 5}和数字3,由于3在这个数组中出现了4次,因此输出4。

    问题(2)0到n-1中缺失的数字

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

    问题(3)数组中数值和下标相等的元素

    假设一个单调递增的数组里的每个元素都是整数并且是唯一的。

    请编程实现一个函数找出数组中任意一个数值等于其下标的元素。例如,在数组{-3, -1,1, 3, 5}中,数字3和它的下标相等。

    问题分析

    问题(1)分析

    思路一:

    对于一个排序数组,最容易想到的方法就是二分查找,不过重要的是找到第一个和最后一个3,所以要改进二分法:对于中间数字等于3的情况,这时可以分类讨论如下:

    1. 如果中间数字的前一个数字也等于3,说明第一个3在前面,继续在前半段查找第一个3;

    2. 如果中间数字的前一个数字不等于3,说明该位置是第一个3;

    3. 如果中间数字的后一个数字也等于3,说明最后一个3在后面,继续在后半段查找最后一个3;

    4. 如果中间数字的后一个数字不等于3,说明该位置是最后一个3;

    思路二:

    由于数组是排序的整数,可以直接找k-0.5和k+0.5应该在数组中哪个位置。这种方法一目了然。(不要从头到尾遍历,走二分查找吧)

    问题(2)分析

    数组形式大概是这样的:

    在这里插入图片描述

    由于是排序数组,大都走二分查找算法,结合上图可知:

    当中间数字等于其下标时,我们在后半部分查找;

    当中间数字不等于其下标时:

    1. 如果中间数字的前一个数字也不等于其下标,则在前半部分查找;

    2. 如果中间数字的前一个数字等于其下标,则说明中间数字的下标即为我们所要找的数字。

    问题(3)分析

    排序数组继续走二分查找:

    1. 当中间数字等于其下标时,中间数字即为所求数字;

    2. 当中间数字大于其下标时,在左半部分区域寻找;

    3. 当中间数字小于其下标时,在右半部分区域寻找;

    问题解答

    问题(1)

    思路一:

        public int GetNumberOfK(int [] array , int k) {
            if(array==null || array.length<=0) {
                return 0;
            }
            int firstK = getFirstK(array,0,array.length-1,k);
            if(firstK == -1) {
                return 0;
            }
            int lastK = getLastK(array,firstK,array.length-1,k);
            return lastK-firstK+1;
        }
    
        private int getFirstK(int[] arr, int start, int end,int k){
            if(start>end) {
                return -1;
            }
            int mid = (start+end)>>1;
            if(arr[mid]==k){
                if( mid == 0 ||arr[mid-1]!=k ) {
                    return mid;
                } else {
                    end = mid-1;
                }
            } else if (arr[mid]<k){
                start = mid+1;
            } else {
                end = mid-1;
            }
            return getFirstK(arr,start,end,k);
        }
    
        private int getLastK(int[] arr, int start, int end,int k){
            if(start>end) {
                return -1;
            }
            int mid = (start+end)>>1;
            if(arr[mid]==k){
                if(mid==arr.length-1 || arr[mid+1]!=k ) {
                    return mid;
                } else {
                    start = mid+1;
                }
            } else if(arr[mid]<k){
                start = mid+1;
            } else {
                end = mid-1;
            }
            return getLastK(arr,start,end,k);
        }
    

    思路二:

      public int GetNumberOfK(int [] arr , int k) {
            if(arr==null || arr.length<=0) {
                return 0;
            }
            int first = getLoc(arr, k , k-0.5);
            int last = getLoc(arr,k,k+0.5);
            return last-first;
        }
        
        private int getLoc(int[]arr, int k, double m){ 
            int start=0,end=arr.length-1;
            while(start <= end){
                int mid=(start+end)>>1;
                if(arr[mid]>m){
                    end=mid-1;
                } else {
                    start=mid+1;
                }
            }
            return start;
        }
    

    问题(2)

        public int getNumberSameAsIndex(int[] arr) {
            if(arr==null || arr.length<=0) {
                // 表示错误
                return -1;  
            }
            int low=0;
            int high=arr.length-1;
            while(low<=high) {
                int mid= (high+low)>>1;
                if(arr[mid]>mid) {
                    high=mid-1;
                } else if(arr[mid]<mid) {
                    low=mid+1;
                } else {
                    return mid;
                }
            }
            return -1;
        }
    

    问题(3)

        public int getNumberSameAsIndex(int[] arr) {
            if(arr==null || arr.length<=0) {
                // 表示错误
                return -1;  
            }
            int low=0;
            int high=arr.length-1;
            while(low<=high) {
                int mid= (high+low)>>1;
                if(arr[mid]>mid) {
                    high=mid-1;
                } else if(arr[mid]<mid) {
                    low=mid+1;
                } else {
                    return mid; 
                }
            }
            return -1;
        }
    
  • 相关阅读:
    第一期站立会议7(11.21 个人)
    第一期站立会议6(11.20 个人)
    第一期站立会议5(11.19个人)
    第一期站立会议4(11.18个人)
    第一期站立会议3(11.17个人)
    第一期站立会议2(11.16个人)
    第一期站立会议1(11.15 个人)
    第二阶段第三次站立会议
    对第一阶段提出意见的总结及改进方案
    第二阶段第二次站立会议
  • 原文地址:https://www.cnblogs.com/JefferyChenXiao/p/12246741.html
Copyright © 2020-2023  润新知