算法每日一题笔记 —— 704.二分查找

上学的时候,刷题真的是废寝忘食,学校的题库被来回手写了三遍。

工作几年后,终究还是还给老师了,今天继续捡起来。

我们有一个算法刷题群,每周群主会安排 4 道题,节假日没题目。想要一起刷题的小伙伴可以加我微信 zzh0838

1. 数组理论基础

定义

数组是存放在连续内存空间上的相同数据类型的集合。

举个例子:

特点

数组有三个特点:

  • 下标从 0 开始
  • 内存空间连续
  • 数据类型相同

成员删除

删除数组成员,需要使用覆盖的方式:

二维数组

理解二维数组:

C++ 中二维数组在(虚拟)地址空间上是连续的。

cpp 复制代码
void test_arr() {
    int array[2][3] = {
		{0, 1, 2},
		{3, 4, 5}
    };
    cout << &array[0][0] << " " << &array[0][1] << " " << &array[0][2] << endl;
    cout << &array[1][0] << " " << &array[1][1] << " " << &array[1][2] << endl;
}

int main() {
    test_arr();
}

输出:

bash 复制代码
0x7ffee4065820 0x7ffee4065824 0x7ffee4065828
0x7ffee406582c 0x7ffee4065830 0x7ffee4065834

java 二维数组在(虚拟)地址空间上是否连续,取决于 java 虚拟机的实现。一种可能得实现如下:

2. 二分查找

题目地址:leetcode.cn/problems/bi...

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:

makefile 复制代码
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例 2:

makefile 复制代码
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

二分查找的前提

  • 数组有序
  • 数组无重复元素

二分查找的难点

对区间的定义没有想清楚,区间的定义就是不变量

写法一

第一种写法,我们定义 target 是在一个在左闭右闭的区间里,也就是left, right (这个很重要非常重要)。

cpp 复制代码
// 版本一
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
        while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <=
            int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
            if (nums[middle] > target) {
                right = middle - 1; // target 在左区间,所以[left, middle - 1]
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,所以[middle + 1, right]
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};
  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)

写法二

如果说定义 target 是在一个在左闭右开的区间里,也就是[left, right) ,那么二分法的边界处理方式则截然不同。

cpp 复制代码
// 版本二
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
        while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            int middle = left + ((right - left) >> 1);
            if (nums[middle] > target) {
                right = middle; // target 在左区间,在[left, middle)中
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,在[middle + 1, right)中
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};
  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)

参考资料

相关推荐
AskHarries2 小时前
如何建立关键词库
程序员
老马95272 小时前
把酒言欢
程序员
老马95272 小时前
赴佳期
程序员
Tisfy2 小时前
LeetCode 3090.每个字符最多出现两次的最长子字符串:二重循环 / 滑动窗口
算法·leetcode·字符串·题解·模拟·双指针·滑动窗口
-dzk-2 小时前
【技巧】LC 136.只出现一次的数字
算法·异或
有点。2 小时前
C++二叉树二(练习题)
数据结构·c++·算法·图论
专注仿真3 小时前
问答大模型技术方案算法实现-RAPTOR树构建算法与BEG集成使用
python·算法
众人皆醒我独醉3 小时前
AI 工作负载可观测性:DCGM + Prometheus + Grafana
面试·llm·gpu
西门老铁3 小时前
JWT 是什么?三段式结构、签名原理与 6 个安全坑一次讲透
后端·面试
zlinear数据采集卡4 小时前
数据采集卡从入门到精通(10):采样率与分辨率的核心关系——反比律、架构分布与过采样
arm开发·嵌入式硬件·算法·fpga开发·架构·开源