剑指Offer:数字在排序数组中出现的次数

剑指Offer:数字在排序数组中出现的次数


题目:

在这里插入图片描述

分析:

在排序数组中查找 → \rightarrow 二分查找

二分查找

一开始用下图中绿色的那种写法,然后发现找不到左边界(有双下划线的表示进行了比较,可以看出左边界没有被比较过).
所以换成了红色的那种.
在这里插入图片描述
反正二分查找记熟就是了.再总结一下伪代码:

if (arr.size() <= 1) 
	// 特殊处理
int left = 0, right = arr.size(), mid;
while (true) {
	mid = (left + right) / 2;
	if (arr[mid] == expect) // 找到了. return
	if (mid == left) // arr 中没有这个数. return
	if (arr[mid] > expect) right = mid;
	if (arr[mid] < expect) left = mid;
}

这道题对应的二分查找

如图(图里的 ik 搞错了,应该是 5,但是下面的计算过程用了 4,不过道理都一样):
在这里插入图片描述

代码:

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        if (data.empty()) return 0;
        if (data.size() == 1) {
            if (data[0] == k) return 1;
            else return 0;
        }
        
        int left = 0, right = data.size(), mid = 0;
        while (true) {
            mid = (left + right) / 2;
            if (data[mid] == k)
                return findFirstNotK(data, k, mid, right) - findFirstK(data, k, left, mid);
            if (mid == left) return 0; // not found
            if (data[mid] > k) right = mid;
            if (data[mid] < k) left = mid;
        }
    }
    
    int findFirstK(vector<int>& data, int k, int left, int right) {
        int mid = 0;
        while (right - left > 1) {
            mid = (left + right) / 2;
            if (data[mid] != k) left = mid;
            else right = mid;
        }
        if (data[left] == k) return left;
        return right;
    }
    
    int findFirstNotK(vector<int>& data, int k, int left, int right) {
        int mid = 0;
        while (right - left > 1) {
            mid = (left + right) / 2;
            if (data[mid] != k) right = mid;
            else left = mid;
        }
        return left + 1;
    }
};

另外一种解法

由于给出的数组中都是整数,当求 k 的个数时,我们就可以用同一个二分查找函数分别找 k - 0.5k + 0.5 应该出现的位置.
如下图所示,注意左边界的特殊情况.
在这里插入图片描述

代码如下:

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        if (data.empty()) return 0;
        if (data.size() == 1) {
            if (data[0] == k) return 1;
            else return 0;
        }
        return binarySearch(data, k + 0.5) - binarySearch(data, k - 0.5);
    }
    int binarySearch(vector<int>& data, double d) {
        int left = 0, right = data.size(), mid;
        while (right - left > 1) {
            mid = (left + right) / 2;
            if (data[mid] > d) right = mid;
            if (data[mid] < d) left = mid;
        }
        return data[left] < d ? right : left;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值