80岁老爷爷学算法第一天——二分查找

0 阅读3分钟

80岁老爷爷学算法之二分查找

今日老爷爷闲来无事,打开了leetcode,并凑巧打开了0x3f的二分查找题单,于是开始了学算法的一天,爷爷不懂什么是二分查找,戴着老花镜盯着屏幕上的 “有序数组、左闭右闭、边界收缩”,眉头皱成一团,嘴里还小声嘀咕:“这年轻人写的东西,怎么比当年的算盘口诀还绕。”

老爷爷看到了有一个0x3f的b站讲解视频,爷爷不懂b站是干什么的,只知道孙子总在b站看番,于是他不愿意点开这个链接,只能自己摸索了,于是开始尝试leetcode34. 在排序数组中查找元素的第一个和最后一个位置,老爷爷想用for循环去从头遍历,可是题目要求时间复杂度O(logn),老爷爷心想看来只能用所谓什么所谓的二分查找了,老爷爷上来先模仿了一下二分左闭右闭固定模板:

while (左 <= 右):没找完就接着找
  算中间位置
  中间数 >= 目标:答案在左边,右边界往左缩
  中间数 < 目标:答案在右边,左边界往右缩
循环结束:left就是第一个>=目标的位置

爷爷英语不好,但也尝试了一下C++语言,看来爷爷的学习能力还是很强的:

while (left <= right) {
      int mid = left + (right - left) / 2; 
      if (nums[mid] >= target) {
         right = mid - 1;
      } else {
         left = mid + 1;
      }
}

当然,老爷爷虽然年龄大,但还是比较理智的,让mid = left + (right - left) / 2,这样能避免两个大数相加导致的数值溢出问题。 同理,爷爷又写了一下查找最后target的代码:

while (left <= right) {
       int mid = left + (right - left) / 2;
       if (nums[mid] <= target) {
           left = mid + 1;
       } else {
           right = mid - 1;
       }
}

接下来,可以正式解答这道题了,理智的爷爷首先看到了示例3

示例 3:

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

于是他先进行了空数组判定:

if(nums.empty())  return {-1,-1};

现在爷爷已经学得差不多了,于是整理了一个完整的C++代码:

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if(nums.empty())  return {-1,-1};

        int left = 0,right = nums.size()-1;

        while (left <= right) {
            int mid = left + (right - left) / 2; 
            if (nums[mid] >= target) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }

        int start = left;
        if (start >= nums.size() || nums[start] != target) {
            return {-1, -1};
        }

        left = 0;
        right = nums.size() - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] <= target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        int end = right;

        return {start, end};
    }
};

这里细心的爷爷写了一个小细节:if (start >= nums.size() || nums[start] != target) return {-1, -1};

// 两道安检门,缺一不可
if (start越界  || start位置的数不是target) {
  返回[-1,-1],说明没找到目标值
}

他笑着说:“这就跟我去粮站领粮食一样,先看粮本够不够数(不越界),再看粮本上的名字对不对(是目标值),少一步都领不了,这代码也是一个理儿,少一步就错!”

最后,老爷爷在力扣上提交了代码,成功ac,时间复杂度也符合了,老爷爷勇闯算法之路第一天学习部分成功结束,接下来就要开始练习了。

可能有人会问,老爷爷都八十岁了,为什么还要学算法?

因为他心里,一直藏着一个独自搭建智能体的梦想。

情节虽然虚构,算法真实有效