在排序数组中查找数字 I(入门算法08)

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

示例:

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

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

解题思路:这个就太简单了吧。。。。没想到会作为我的第八道入门算法,我一度怀疑我是不是看错题了。。。。首先这是一个已经排好序的数组,所以,我们可以遍历我们的数组去找我们的那个值,找到一个我们就让count+1,然后碰到比他大的我们就退出循环就好了。

class Solution {
    public int search(int[] nums, int target) {
        int count = 0;
        for(int i = 0; i < nums.length; i++ ){
            if(nums[i] > target){
                return count;
            }
            if(nums[i] == target){
                count++;
            }
        }
        return count;
    }
}

力扣战绩:
在这里插入图片描述

鉴于这道题过于简单,我又找了一道类似的中等题来做。
题目:在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。

进阶:设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例:

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

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

输入:nums = [], target = 0
输出:[-1,-1]

解题思路:
直观的思路肯定是从前往后遍历一遍。用两个变量记录第一次和最后一次遇见 target 的下标,但这个方法的时间复杂度为 O(n),没有利用到数组升序排列的条件。

由于数组已经排序,因此整个数组是单调递增的,我们可以利用二分法来加速查找的过程。

考虑 target 开始和结束位置,其实我们要找的就是数组中「第一个等于 target 的位置」(记为leftIdx)和「第一个大于 target 的位置减一」(记为rightIdx)。

二分查找中,寻找 leftIdx 即为在数组中寻找第一个大于等于target 的下标,寻找 rightIdx 即为在数组中寻找第一个大于 target 的下标,然后将下标减一。两者的判断条件不同,为了代码的复用,我们定义 binarySearch(nums, target, lower) 表示在 nums 数组中二分查找 target 的位置,如果lower 为true,则查找第一个大于等于 target 的下标,否则查找第一个大于target 的下标。

最后,因为target 可能不存在数组中,因此我们需要重新校验我们得到的两个下标 leftIdx 和 rightIdx,看是否符合条件,如果符合条件就返回 [leftIdx,rightIdx],不符合就返回 [-1,-1]。

class Solution {
    
    public int[] searchRange(int[] nums, int target) {
        int leftIdx = binarySearch(nums, target, true);
        int rightIdx = binarySearch(nums, target, false) - 1;
        if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {
            return new int[]{leftIdx, rightIdx};
        } 
        return new int[]{-1, -1};
    }

    public int binarySearch(int[] nums, int target, boolean lower) {
        int left = 0, right = nums.length - 1, ans = nums.length;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (nums[mid] > target || (lower && nums[mid] >= target)) {
                right = mid - 1;
                ans = mid;
            } else {
                left = mid + 1;
            }
        }
        return ans;
    }
}

力扣战绩:
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值