剑指 Offer 53 - I. 在排序数组中查找数字 I

目录

题目

解题思路1——暴力破解

解题思路2——浅浅的运用一下二分查找的思想

解题思路3——纯二分查找的递归

题解1——暴力破解

题解2——二分查找+顺序查找

题解3——递归+二分查找

总结


题目

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

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8

输出: 2

示例 2:

输入: nums = [5,7,7,8,8,10], target = 6

输出: 0

提示:

  • 0 <= nums.length <= 10^5

  • -10^9 <= nums[i] <= 10^9

  • nums 是一个非递减数组

  • -10^9 <= target <= 10^9




解题思路1——暴力破解

既然需要在一个数组中统计某一个数出现的次数,那么将数组中的每一个元素都和该数进行比较,如果相等则出现的次数增加1,如果不相等则直接比较下一个元素。这是一定可以得到正确答案的做法。




解题思路2——浅浅的运用一下二分查找的思想

很有意思的是,提示中指明了给定的数组是一个非递减数组,那么,给定的这个数组必定是有序的,对有序数组进行查找,时间复杂度为对数阶的二分查找(折半查找)算得上是一个活跃分子。

但是,二分查找的特点是只对目标值命中一次或者零次,如果要用来统计出现的次数,好像有些不太容易。

那么,有一种简单的想法就是:使用二分查找找到目标值所在的位置,如果不命中,那么出现的次数为0;如果命中,由于目标值在数组中会出现若干次,那么便可以以找到的位置为起点,向两侧查找,找到和目标值不相等的元素值便停止查找,这样一来,便可以比暴力破解少进行一些比较。




解题思路3——纯二分查找的递归

使用二分查找找到目标值的位置,之后在该位置的基础上向两侧进行查找这样的思路中,向两侧进行查找时使用的是顺序比较的方式进行的,那么既然是查找,除了顺序比较的方式,也可以使用二分查找的方式进行查找,这样一来便纯粹地使用二分查找进行统计了。

但是这三种思路的时间开销来看,还真没有什么差别。

那么,纯粹使用二分查找,便可以使用递归的形式来进行,递归的示意图如下:

那么,便可以得到这样一个结论:

 

 




题解1——暴力破解

class Solution {
    public int search(int[] nums, int target) {
        int count = 0;
        for(int i=0;i<nums.length;i++){
            if(nums[i] == target){
                count++;
            }
        }

        return count;
    }
}



题解2——二分查找+顺序查找

class Solution {
    public int search(int[] nums, int target) {
        //如果数组为空,那必然是找不到的
        if(nums.length == 0){
            return 0;
        }
        //如果数组只有一个元素,那么只判断这个元素就行
        if(nums.length == 1){
            if(nums[0] == target){
                return 1;
            }else{
                return 0;
            }
        }
        int left = 0;   //左界
        int right = nums.length-1;  //右界
        int mid = right/2;  //中间
        int count = 0;  //统计出现次数
        while(left<=right){
            mid = (right - left)/2 + left;
            if(nums[mid] < target){
                left = mid + 1;
            }
            if(nums[mid] > target){
                right = mid - 1;
            }
            if(nums[mid] == target){
                break;
            }
        }
        for(int i=mid;i>=0;i--){
            //统计左侧区域的次数
            if(nums[i] == target){
                count++;
            }else{
                break;
            }
        }
        for(int i=mid;i<=right;i++){
            //统计右侧区域的次数
            if(nums[i] == target){
                count++;
            }else{
                break;
            }
        }

        if(count == 0){
            return 0;
        }
        return count - 1;
    }
}



题解3——递归+二分查找

class Solution {
    static int count = 0;
    public int search(int[] nums, int target) {
        count = 0;
        binarySearch(nums,0,nums.length-1,target);

        return count;

    }

    //二分查找
    public static void binarySearch(int[] nums,int left,int right,int target){
        if(left <= right){
            int mid = (right - left)/2 + left;
            if(nums[mid] == target){
                count++;
                binarySearch(nums,left,mid-1,target);
                binarySearch(nums,mid+1,right,target);
            }
            if(nums[mid] > target){
                binarySearch(nums,left,mid-1,target);
            }
            if(nums[mid] < target){
                binarySearch(nums,mid+1,right,target);
            }
        }
    }
}



总结

三种解题方法在时间开销上没什么差别,但是在空间的开销上有些差别。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值