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

题目一

/**
 * 面试题53:在排序数组中查找数字
 * 题目一:统计一个数字在升序数组中出现的次数。
 * 输入:[1,2,3,3,3,3,4,5],3
 * 输出:4
 * @author
 * @create 2021-04-07 18:04
 */
public class Solution53_1 {
    public static void main(String[] args) {
        int[] array = {1,2,3,3,3,3,4,5};
        int numberOfKBinarySearch = getNumberOfKBinarySearchThrid(array, 3);
        System.out.println(numberOfKBinarySearch);
    }

    /**
     * 方法一:直接计数
     * 时间复杂度O(n)
     * @param array
     * @param k
     * @return
     */
    public static int getNumberOfK(int [] array , int k) {
        if (array == null || array.length == 0){
            return -1;
        }
        int count = 0;
        for (int j : array) {
            if (j == k){
                count++;
            }
        }
        return count;
    }

    /**
     * 方法二:二分查找到k,然后左右遍历,时间复杂度为O(n)
     * @param array
     * @param k
     * @return
     */
    public static int getNumberOfKBinarySearch(int [] array , int k) {
        if (array == null || array.length == 0){
            return -1;
        }
        //也可以用Arrays.binarysearch()
//        int index = Arrays.binarySearch(array,k);
        int index = binarySearch(array, k, 0, array.length - 1);
        if (index < 0){
            return -1;
        }
        int count = 1;

        for (int i = index-1; i >= 0; i--) {
            if (array[i] == k){
                count++;
            }else {
                break;
            }
        }
        for (int i = index+1; i < array.length; i++) {
            if (array[i] == k){
                count++;
            }else {
                break;
            }
        }
        return count;
    }

    public static int binarySearch(int[] array, int target, int left, int right){
        if (left > right){
            return -1;
        }
        while (left < right){
            int mid = (left + right) / 2;
            if (array[mid] > target){
                right = mid - 1;
            }else if (array[mid] < target){
                left = mid + 1;
            }else {
                return mid;
            }
        }
        return -1;
    }

    /**
     * 方法三:二分法找到第一个k和最后一个k
     * 时间复杂度O(logn)
     * @param array
     * @param k
     * @return
     */
    public static int getNumberOfKBinarySearchThrid(int [] array , int k) {
        if (array == null || array.length == 0){
            return -1;
        }
        int fristK = getFristK(array,k,0,array.length-1);
        int lastK = getLastK(array,k,0,array.length-1);
        return lastK - fristK + 1;
    }

    public static int getFristK(int [] array,int k, int left, int right){
        if (left > right){
            return -1;
        }
        int mid = (left + right) / 2;

        if (array[mid] > k){
            right = mid - 1;
        }else if (array[mid] < k){
            left = mid + 1;
        }else {
            if ((mid > 0 && array[mid - 1] != k) || mid == 0){
                return mid;
            }else {
                right = mid - 1;
            }
        }
        return getFristK(array,k,left,right);
    }

    public static int getLastK(int [] array,int k, int left, int right){
        if (left > right){
            return -1;
        }
        int mid = (left + right) / 2;

        if (array[mid] > k){
            right = mid - 1;
        }else if (array[mid] < k){
            left = mid + 1;
        }else {
            if ((mid < array.length-1  && array[mid + 1] != k) || mid == array.length-1){
                return mid;
            }else {
                left = mid + 1;
            }
        }
        return getLastK(array,k,left,right);
    }


}

题目二及题目三

import org.junit.Test;

/**
 * 面试题53:第二题
 * 题目二:0~n-1中缺失的数字。
 * 一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。
 * 在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
 * @author
 * @create 2021-04-07 20:31
 */
public class Solution53_2 {
    public static void main(String[] args) {
        int[] array = {0,1,2,3,5};
        int missingNumber = getMissingNumber(array);
        System.out.println(missingNumber);
    }

    public static int getMissingNumber(int[] array){
        if (array == null || array.length == 0){
            return -1;
        }
        int left = 0;
        int right = array.length-1;
        // 二分查找
        while (left <= right){
            int mid = (left + right) / 2;
            if (array[mid] != mid){//如果中间索引的值不等于中间索引,说明缺少的值为当前索引或左边的索引
                if (mid == 0 || array[mid - 1] == mid - 1){
                    //如果mid为0或者mid前一个值与下标值相等,说明当前索引是第一个与下标不相等的值
                    return mid;
                }
                right = mid - 1;//否则就向左边查找
            }else {
                left = mid + 1;//相等的情况下向右边查找
            }
        }
        return -1;
    }


    @Test
    public void test(){
        int[] array = {-3,-1,1,3,5};
        int numberSameAsIndex = getNumberSameAsIndex(array);
        System.out.println(numberSameAsIndex);
    }

    /**
     * 题目三:数组中数值和下标相等的元素-->二分查找
     * 题目:假设一个单调递增的数组里的每个元素都是整数并且是唯一的。请编写实现一个函数,找出数组中任意一个数值等于其下标的
     * 元素。例如,在数组{-3,-1,2,3,5}中,数字3和它的下标相等
     * @param number
     * @return
     */
    public static int getNumberSameAsIndex(int[] number){
        if (number == null || number.length == 0){
            return -1;
        }
        int left = 0;
        int right = number.length - 1;
        while (left <= right){
            int mid = (left + right) / 2;
            if (number[mid] > mid){
                right = mid - 1;
            }else if (number[mid] < mid){
                left = mid + 1;
            }else {
                return mid;
            }
        }
        return -1;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值