先说结论:我本来以为“数组 Day1”这种题就是送分,结果跟着代码随想录的数组专题把第一天内容重新刷完之后,才发现以前很多“会做”其实是“背下来了”。数组这类题目表面上只考增删改查、二分查找、双指针,实际上它把所有算法基本功全串在了一起:循环不变量的把握、区间边界的处理、原地操作的代价、返回值与真实数组长度的区分。这篇博客我会按照代码随想录数组专题第一天的思路,把二分查找、移除元素、有序数组平方这几类最典型的问题拆开讲清楚,包含完整 C++ 实现、每一步为什么要这么写、以及我实际刷题时踩过的坑。适合刚开始刷 LeetCode、或者刷了一段时间但总是边界出错的人。
1. 数组专题第一天,到底在练什么
1.1 连续内存带来的三大特性
数组是所有数据结构里最“朴素”的一种:元素在内存中连续存放,通过下标就能在 O(1) 时间内随机访问任意元素。这个特性看起来简单,但它直接决定了后续所有操作的思维模式。比如“删除一个元素”,数组不像链表那样改一下指针就行,必须把后面所有元素往前覆盖;再比如“查找一个元素”,因为数据连续且通常有序,我们才能高效地使用二分查找而不是每次都遍历。
理解连续内存还有一个容易被忽略的点:数组的长度是固定的。在 C++ 中,栈上原生数组 int a[10] 的长度编译期就确定了;就算用 vector,底层也是一片连续堆内存,扩容时要把旧数据搬到新位置。刷题时很多 bug 的根源就是忘了“数组不能真正删除元素,只能覆盖”,于是越写越乱。
代码随想录把数组专题放在最前面,我觉得很合理。它不要求你掌握复杂数据结构,却逼你先想清楚四个问题:区间定义是什么、指针怎么移动、循环什么时候结束、返回结果到底代表什么。这四个问题一旦解决,后面学链表、二叉树、动态规划时很多边界判断思路都是相通的。
1.2 Day1 题目怎么安排更合理
代码随想录数组第一天的内容一般围绕二分查找、移除元素这类基础题展开,有精力的话还会加上有序数组的平方。我建议按“先理解线性操作,再接触双指针优化”的顺序来安排:
- 先做 704 二分查找,重点练区间边界;
- 再做 27 移除元素,重点练快慢指针和原地操作;
- 有能力再做 977 有序数组的平方,练左右指针和“从后往前填”的思路。
这样做的好处是难度梯度非常顺。二分查找让你感受“循环条件差一个等号就全错”的残酷;移除元素让你从 O(n^2) 的暴力写法进化到 O(n) 的双指针写法;有序数组的平方则把负数平方后顺序变化的问题和双指针结合起来,刚好覆盖数组题里最常见的两类思维模型。Day1 不用贪多,把这三道题做透,比盲目刷十道题更有用。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 二分查找:循环不变量就是你的安全带
2.1 闭区间写法与防溢出模板
先给出最推荐新手掌握的闭区间写法:
cpp复制int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
这个模板的关键点是:我们规定 target 只可能存在于 [left, right] 这样一个闭区间里。所以在 while 判断时使用 left <= right,因为当 left == right 时,区间里还有一个元素需要检查。每次比较完 nums[mid] 和 target 后,必须把 mid 排除在下一轮区间外,所以更新规则是 left = mid + 1 或 right = mid - 1。
计算 mid 时我习惯写 left + (right - left) / 2,而不是 (left + right) / 2。原因很简单:当 left 和 rig
