剑指Offer(三十七):数组在排序数组中出现的次数--python

本文探讨了在已排序数组中统计特定数字出现次数的三种高效算法。第一种使用二分查找确定目标数前后位置;第二种利用Python内置count()函数简洁实现;第三种精确定位首次与末次出现位置,适用于大规模数据处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

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

思路:

看到排序数组,又需要遍历,首先想到二分查找,过程中非科班生基础薄弱暴露无遗,本篇可能罗里吧嗦,因为记录了完整填坑历程,适合和博主一样的菜鸟看。。。(tips:所有代码博主是在jupyter里敲的,勿犯眼高手低的毛病建议copy过去自己试一下)

方法一:

class Solution:
    def test_in_class():
        print('test_in_class')
        
    def biSearch(self, array, k):
        low = 0
        high = len(array) - 1

        #类方法和普通方法的调用
        Solution.test_in_class()
        test_out_class()

        while(low <= high):#跳出时low>high
            mid = low + (high - low)//2
            if k == array[mid]:
                return mid
            if array[mid] > k:
                high = mid - 1
            if array[mid] < k:
                low = mid + 1
        return low
def test_out_class():
    print('test_out_class')

if __name__ == '__main__':    
    a = Solution()
    print(a.biSearch([1,2],2))

由此可以想到搜索k-0.5和k+0.5这两个确定数应该插入的位置,然后相减即可,如[1,2,2,2,3,4]查找1.5和2.5会返回2和3的位置索引,即在这两处插入,直接相减即可:

# -*- coding:utf-8 -*-
class Solution:
    def GetNumberOfK(self, data, k):
        #搜索k-0.5和k+0.5这两个确定数应该插入的位置
        return self.biSearch(data, k+0.5) - self.biSearch(data, k-0.5)
    
    def biSearch(self, data, k):
        low = 0
        high = len(data) - 1
        while(low <= high):
            mid = low + (high - low)//2
            if data[mid] > k:
                high = mid - 1
            if data[mid] < k:
                low = mid + 1
        return low
                

方法二:

一行代码面试官直接录取有木有(手动滑稽)

# -*- coding:utf-8 -*-
class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        return data.count(k);

方法三:

查找第一次k出现的位置  和  最后一次k出现的位置,相减。

摸索的二分查找三部曲:

derection:从左往右,考虑上溢出(need:low < len(data)),考虑输入小数时找不到(need:data[low]==k),return low
target:第一次k出现的位置,即找大于等于k的第一个数
method:不满足(data[mid]<k)则继续前进

class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        left = self.getFirst(data,k)
        right = self.getLast(data,k)
        #返回左右下标间k值的个数,都找不到返回0
        return right - left + 1 if left != -1 and right != -1 else 0
    
    #返回数组data中第一个值为k的下标,找不到为-1
    def getFirst(self,data, k):
        low = 0
        high = len(data) - 1
        while(low<=high):
            #从左向右,考虑上溢出(need:low < len(data)),考虑小数时找不到(need:data[low]==k),return low
            #target:找大于等于k的第一个数
            #method:不满足(data[mid]<k)则继续前进
            mid = low + (high - low)//2
            if data[mid] < k:
                low = mid + 1
            else:
                high = mid - 1
        return low if low < len(data) and data[low] == k else -1
    
    #返回数组data中最后一个值为k的下标,找不到为-1
    def getLast(self,data, k):
        low = 0
        high = len(data) - 1
        while(low<=high):
            #从右向左,考虑下溢出(need:high > -1),考虑小数时找不到(need:data[high]==k),return high
            #target:找小于等于k的第一个数
            #method:不满足(data[mid]>k)则继续前进
            mid = low + (high - low)//2
            if data[mid] > k:
                high = mid - 1
            else:
                low = mid + 1
        return high if high > -1 and data[high] == k else -1
#用如下数组依次测试
#data = [1,2,2,2,3,4,5]
#data = [1,3,3,3,3,4,5]
#data = [3]
#a = Solution()
#print(a.GetNumberOfK(data, 3))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值