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

题目

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

示例 1:

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

示例 2:

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

限制:

  • 0 <= 数组长度 <= 50000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof

解题思路

排序数组:直接想到二分法和双指针

本题使用二分法来解决

思路一:

  • 查找目标值的右边界right
  • 查找目标值的左边界left
  • 计算出现次数right - left - 1

思路二:

  • 查找目标值的右边界r1
  • 查找目标值 - 1的右边界r2
  • 计算出现次数r1 - r2

代码

思路一:

class Solution {
    public int search(int[] nums, int target) {
        // 本题使用二分法解决
        int l = 0;
        int r = nums.length - 1;
        // 判断下标是否越界,最小的元素是否大于目标值,最大元素是否小于目标值
        if (r < 0 || nums[l] > target || nums[r] < target) {
            return 0;
        }

        // 查找目标值的右边界
        while (l <= r) {
            int m = l + ((r - l) >> 1);
            if (nums[m] <= target) {
            	// 当nums[m] == target时,因为此时是为了查找目标值的右边界,所以也是进行左边界右移
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
        int right = l;

        // 提前判断目标值是否存在
        if (r >= 0 && nums[r] != target) {
            return 0;
        }

        // 计算目标值的左边界
        // 记得重置左指针
        l = 0;
        while (l <= r) {
            int m = l + ((r - l) >> 1);
            if (nums[m] < target) {
                l = m + 1;
            } else {
            	// 当nums[m] == target时,因为此时是为了查找目标值的左边界,所以也是进行右边界左移
                r = m - 1;
            }
        }
        int left = r;

        // 计算长度
        return right - left - 1;
    }
}

思路二:

class Solution {

    public int search(int[] nums, int target) {
        // 本题使用二分法解决
        int l = 0;
        int r = nums.length - 1;
        // 判断下标是否越界,最小的元素是否大于目标值,最大元素是否小于目标值
        if (r < 0 || nums[l] > target || nums[r] < target) {
            return 0;
        }

        // 查找目标值的右边界和目标值 - 1的右边界
        return binarySearch(nums, l, r, target) - binarySearch(nums, l, r, target - 1);
    }

    private int binarySearch(int[] nums, int l, int r, int target) {
        // 查找目标值的右边界
        while (l <= r) {
            int m = l + ((r - l) >> 1);
            if (nums[m] <= target) {
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
        return l;
    }
}

复杂度

  • 时间复杂度:O(logn),执行两次二分查找,二分查找时间复杂度为logn
  • 空间复杂度:O(1),占用常数级额外空间
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值