剑指Offer_53 在排序数组中查找数字

package 剑指Offer;

public class 剑指53_在排序数组中查找数字 {
    //统计一个数字在排序数组中出现的次数。例如:输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在数组中出现4次,所以返回结果4
    //思路:因为数组是有序的,所以采用二分法查找,当找到一个k时,因为可能前面或者后面都有k,如果从当前找的到位置往两头开始遍历,那么有可能整个数组为一样的数,所以时间复杂度O(n)
    //所以,采用当找到中间数k的时候,再对前后两部分分别使用二分法查找第一个k和最后一个k,如果不存在返回-1

    public static void main(String[] args) {
        int[] nums = {1, 2, 2, 2, 3, 3, 3, 5};
        int target = 2;
        System.out.println(getTimes(nums, target));

    }

    public static int getTimes(int[] nums, int target) {
        if (nums == null || nums.length == 0) return -1;

        int first = getFirst(nums, 0, nums.length - 1, target);
        int last = getLast(nums, 0, nums.length - 1, target);
        if (first != -1 && last != -1) {
            return last - first + 1;
        }
        return -1;
    }

    public static int getFirst(int[] nums, int start, int end, int target) {
        //二分法查找,必须使用<=。因为比如:array[3] = {1, 3, 5};待查找的键为5,
        // 此时在(low < high)条件下就会找不到,因为low和high相等时,指向元素5,但是此时条件不成立,没有进入while()中
        while (start <= end) {
            int mid = (start + end) / 2;
            int middleNum = nums[mid];
            if (middleNum == target) {
                //进行递归

                //判断前面是否为一样的
                if (mid > 0 && nums[mid - 1] != target || mid == 0) {
                    //前面不一样,直接返回下表
                    return mid;
                } else {
                    //查找前半部分
                    end = mid - 1;
                }
            } else if (middleNum > target) {
                //说明目标值还在前面
                end = mid - 1;
            } else {
                start = mid + 1;
            }
        }


        return -1;
    }

    public static int getLast(int[] nums, int start, int end, int target) {

        while (start <= end) {
            int mid = (start + end) / 2;
            int middleNum = nums[mid];
            if (middleNum == target) {
                //往后面查找最后一个
                if (mid < end && nums[mid + 1] != target || mid == end) {
                    return mid;
                } else {
                    //继续在后半部分递归
                    start = mid + 1;
                }
            } else if (middleNum > target) {
                end = mid - 1;
            } else {
                start = mid + 1;
            }
        }

        return -1;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值