剑指-面试题53-1 在排序数组中查找数字

在排序数组中查找数字

题目
统计一个数字在排序数组中出现的次数。 0 < = 数 组 长 度 < = 50000 0 <= 数组长度 <= 50000 0<=<=50000

**思路 **
        排序数组 nums中的所有数字 target形成一个窗口,记窗口的 左 / 右边界索引分别为 left和 right,分别对应窗口左边 / 右边的首个元素。
        本题要求统计数字 target的出现次数,可转化为:使用二分法分别找到左边界 left和右边界 right ,易得数字target的数量为 r i g h t − l e f t − 1 right - left - 1 rightleft1
在这里插入图片描述
(1)初始化: 左边界 i = 0,右边界 j = len(nums) - 1代表闭区间 [i, j] 。
(2)循环二分: 当i≤j 时循环 (即当闭区间 [i, j]为空时跳出)

  • 计算中点 m = (i + j) // 2m=(i+j)//2 ,其中 “” 为向下取整除法;
  • 若nums[m] < target,则数字 target一定在闭区间 [m + 1, j]中,因此执行 i = m + 1;
  • 若 nums[m] > target ,则数字 target一定在闭区间 [i, m - 1] 中,因此执行 j = m - 1;
  • 若 nums[m] = target ,则右边界 right在闭区间 [m+1, j]中左边界 left 在闭区间 [i, m-1] 中
    分为以下两种情况:
    – 若查找右边界 right,则执行 i = m + 1;(跳出时 i 指向右边界
    – 若查找左边界 left,则执行 j = m - 1;(跳出时 j指向左边界

(3)返回值: 应用两次二分,得到左右边界

(或者python的代码中,right=j left=i,则left和right分别指向第一个和最后一个target,返回right-left+1

时间复杂度 O ( l o g n ) O(logn) O(logn)


C++

class Solution {
public:
    int search(vector<int>& nums, int target) {
        if(nums.empty())
            return 0;
        int n=nums.size();
        int left = 0, right = n-1, mid;
        int x, y;
        while(left<right)                       //找到第一个target
        {
            mid = (left+right)/2;
            if(nums[mid]>=target)
                right = mid;                    
            else
                left = mid+1;
        }
        if (nums[left]!=target)                 //数组中不含target
            return 0;
        x = left;                               //x指向第一个left
        right = n;
        while(left<right)                       //找到最后一个target
        {
            mid = (left+right)/2;
            if(nums[mid]<=target)
                left = mid+1;
            else
                right = mid;
        }
        y = left;                               //y指向最后一个target
        return y-x;
    }
};

python

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        i, j = 0, len(nums)-1
        while i<=j:				#找右边界,最后一个target之后
            m = (i+j)//2
            if nums[m]<=target:
                i = m+1
            else:
                j = m-1
        right = i
        i, j = 0, len(nums)-1
        while i<=j:				#找左边界,第一个target之前
            m = (i+j)//2
            if nums[m]<target:
                i = m+1
            else:
                j = m-1
        left = j
        return right-left-1

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值