【Golang】LeetCode-剑指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


解法一:直接遍历计数/map计数

–执行时间:8 ms --消耗内存:4.1 MB

func search(nums []int, target int) int {
    var time int
    for _,v:=range nums{
        if target<v{
            break
        }
        if target==v{
            time++
        }
    }
    return time
}

解法二:二分查找左右边界

解题思路

  • while(left < right) 在退出循环的时候,一定有 left == right成立

    • 因此,在循环中,不断排除不是目标元素的区间,以确定下一轮搜索的区间,进而确定边界如何设置
    • 在退出循环的时候,根据情况,需要单独做一次判断
  • 在循环体里,对 nums[mid] 与 target 的大小关系的判断,可以二分,也可以三分,本题采用三分去判断,只是为了演示怎么设置边界

    • 先得到目标元素可能在哪个区间里,然后再设置边界,这样不容易出错
    • 二分的好处是只要一边判断是正确的,另一边就是其反面,考虑的内容会少一些
  • 看到边界是 left = mid 的时候,取中间数的计算表达式应该上取整,即在括号里加 1

  • 编码时应该先写主干逻辑,然后分支逻辑作为私有函数。

解题思路引用自作者:liweiwei1419


代码

–执行时间:8 ms --消耗内存:4.1 MB

func search(nums []int, target int) int {
    if len(nums)==0{
        return 0
    }
    if len(nums)==1 && nums[0]!=target{
        return 0
    }

    firstPoint:=getFirstPoint(nums,target)
    if firstPoint==-1{
        return 0
    }

    lastPoint:=getLastPoint(nums,target)
    return lastPoint-firstPoint+1
}

func getLastPoint(nums []int, target int) int{
    left:=0
    right:=len(nums)-1
    for left<right{
        // 注意,以下 nums[mid] < target 以及 nums[mid] == target 的情况可以合并
        // 边界是 left = mid ,取中间数的时候必须 + 1
        mid:=(left+right+1)>>1
        if nums[mid]<target{
            // mid 以及 mid 左边都不是,下一轮搜索区间在 [mid + 1, right]
            left=mid+1
        }else if nums[mid]==target{
            left=mid
        }else{
            // 此时 nums[mid] > target
            // mid 以及 mid 右边都不是,下一轮搜索区间在 [left, mid - 1]
            right=mid-1
        }
    }a
    return right
}

func getFirstPoint(nums []int, target int) int{
    left:=0
    right:=len(nums)-1
    for left<right{
        mid:=(left+right)>>1
        if nums[mid]<target{
            // mid 以及 mid 左边都不是,下一轮搜索区间在 [mid + 1, right]
            left=mid+1
        }else if nums[mid]==target{
            // mid 可能是,mid 右边一定不是,下一轮搜索区间在 [left, mid]
            right=mid
        }else{
            // 此时 nums[mid] > target
            // mid 以及 mid 右边都不是,下一轮搜索区间在 [left, mid - 1]
            right=mid-1
        }
    }
    if nums[left]!=target{
        return -1
    }
    return left
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值