• 二分查找实例1(在排序数组中查找元素的第一个和最后一个位置)


    题目

    给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

    如果数组中不存在目标值 target,返回 [-1, -1]

    你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

    示例 1:

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

    示例 2:

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

    示例 3:

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

    提示:

    • 0 <= nums.length <= 105
    • -109 <= nums[i] <= 109
    • nums 是一个非递减数组
    • -109 <= target <= 109

    算法原理

    二分查找的精髓是二段性,不管数组是否有序,只要数组存在二段性(即数组可以分成两部分),那就可以使用二分查找

    1 利用二分查找左端点

       假设要查找的左端点的值为t,t将整个数组分为两部分:

       区间一内的所有元素小于t   区间二内的所有元素大于等于t

       假设每一次二分mid下标对应的值为x

       a 若是x

       b 若是x>=t 则right = mid  (不能是mid+1,因为mid可能就是最终答案,若是right=mid+1,那么即将检索的区间内没有了答案)

    2 一些细节:

       a 循环条件:left

          不能是left<=right 其一是因为当left==right时已经有答案了,其二是会死循环

          

    b 找中点操作:

       1 mid = left+(right-left)/2  选择这个,当区间元素数为偶数时,选择左侧的为中点

       2 mid = left+(right-left+1)/2  不选这个 当区间元素数为偶数时,选择右侧的为中点

       

    查找左端点时,当区间内只剩下两个元素时 ,选择1,则mid是前一个元素,那么无论是left=mid+1,还是right=mid ,left和right最终都会相等

    而选择2,mid是后一个元素,若是执行right=mid,那么陷入死循环

    3 利用二分查找右端点 

       a 若是x<=t 则left = mid(不能是mid+1,因为mid可能是最终结果)

       b 若是x>t 则right = mid-1

    c 循环条件:left

       求中点:mid = left+(right-left+1)/2  left最终都会等于right 

                     若是选择 mid = left+(right-left)/2,当执行left=mid时,陷入死循环

    代码实现:

    1. class Solution
    2. {
    3. public:
    4. vector<int> searchRange(vector<int>& nums, int target)
    5. {
    6. if(nums.empty())//处理边界情况
    7. {
    8. return {-1,-1};
    9. }
    10. //1 二分找左端点
    11. int left = 0;
    12. int right = nums.size()-1;
    13. while(left
    14. {
    15. int mid = left+(right-left)/2;
    16. if(nums[mid]
    17. {
    18. left = mid+1;
    19. }
    20. else
    21. {
    22. right = mid;
    23. }
    24. }
    25. int begin = 0;
    26. if(nums[left]==target)
    27. {
    28. begin = left;
    29. }
    30. else
    31. {
    32. return {-1,-1};
    33. }
    34. //2 二分找右端点
    35. left = 0;
    36. right = nums.size()-1;
    37. while(left
    38. {
    39. int mid = left+(right-left+1)/2;
    40. if(nums[mid]<=target)
    41. {
    42. left = mid;
    43. }
    44. else
    45. {
    46. right = mid-1;
    47. }
    48. }
    49. return {begin,left};
    50. }
    51. };

  • 相关阅读:
    Java集合大总结——Iterator(迭代器)接口
    【MindSpore产品】【多卡GPU训练功能】参数应该怎么设置
    Word控件Spire.Doc 【页面设置】教程(3):在 C#、VB.NET 中设置 Word 页边距
    redis实现布隆过滤器
    vulnhub之narak
    23、WiFiClient、ESP8266HTTPClient使用
    pyqt环境搭建
    初识网络编程
    kubernetes && kuboard 端口
    【Redis】深入探索 Redis 的数据类型 —— 无序集合 Set
  • 原文地址:https://blog.csdn.net/weixin_73142957/article/details/132737146