LeetCode 20天算法刷题计划第一天:二分查找

前言

hello,大家好,博主开了一个题海求知的专栏,用来记录一些刷题过程中的收获,感谢大家的支持。今天我们开始第一篇文章,有关于二分查找。
在博主写这篇的同时,手机里正在放着英仙座流星雨的直播,很期待一场盛大的流星雨。
在这里插入图片描述
好的,让我们正式开始我们的博文吧。

1.704二分查找

1.1题目链接

https://leetcode-cn.com/problems/binary-search/

1.2题目描述

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

在这里插入图片描述

1.3题目分析

如果我们追根溯源一下,二分查找的思想在我们中小学阶段就已经接触过了。记不记得高中有一种题目是求对数的值的区间,通常作为选择题的前三道出现。我们确定那个区间用到的方法就是二分法。再向前追溯,在小学阶段,有一种很经典的题是用一个天平最快找出10个球中质量不合格的球,我们要每次平均分然后称重。其实这些都是二分的思想。
那么什么是二分法呢?我们来看一下:
在这里插入图片描述

(1)首先,从数组的中间元素开始搜索,如果该元素正好是目标元素,则搜索过程结束,否则执行下一步。
(2)如果目标元素大于/小于中间元素,则在数组大于/小于中间元素的那一半区域查找,然后重复步骤(1)的操作。
(3)如果某一步数组为空,则表示找不到目标元素。
二分法查找的时间复杂度O(logn)。

1.4代码实现

我们这里用的是C语言

int search(int* nums, int numsSize, int target)
{
   int left=0;
   int right=numsSize-1;
   int mid;
   while(left<=right)
   {
       mid=left+(right-left)/2;
       if(target>nums[mid])
       {
           left=mid+1;
       }
       if(target<nums[mid])
       {
           right=mid-1;
       }
       if(target==nums[mid])
       {
           return mid;
       }
   }
   return -1;
}

观察上述代码,我们需要注意一个问题
在这里插入图片描述
这里我们为什么要这样写呢?我们直接写出mid=(left+right)/2.不可以吗?
答案是如果我们这样写也可以编译通过,但这不是一种良好的写法。请试想一下,如果我们的数组非常大,right的值就会很大,很有可能超过int可以表示的范围哦。但如果我们换一种写法:

在这里插入图片描述
所以,我们建议最好采取mid=left+(right-left)/2;这种写法。
还有我们要注意的是+1,-1
在这里插入图片描述
博主在第一次提交的时候没有写,编译没有通过。我们想,既然需要重新改变左值或者右值了,肯定不是mid值了,于是+1,-1可以提高代码效率。

2.278.第一个错误版本

2.1题目链接

https://leetcode-cn.com/problems/first-bad-version/

2.2题目描述

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

在这里插入图片描述

2.3题目分析

我们先理解一下这个题目,在某一个版本后,所以版本都是错误的了,也就是说存在一个版本,在它之前都是正确的,在它之后都是错误的。
在这里插入图片描述
这依旧可以通过二分查找的思想来解决。设定左右边界之后,每次我们都依据左右边界找到其中间的版本,检查其是否为正确版本。如果该版本为正确版本,那么第一个错误的版本必然位于该版本的右侧,我们缩紧左边界;否则第一个错误的版本必然位于该版本及该版本的左侧,我们缩紧右边界。
这样我们每判断一次都可以缩紧一次边界,而每次缩紧时两边界距离将变为原来的一半,因此我们至多只需要缩紧 O(logn) 次。

2.4代码实现

C语言

int firstBadVersion(int n) 
{
    int left = 1, right = n;
    while (left < right) 
    {  // 循环直至区间左右端点相同
        int mid = left + (right - left) / 2;  // 防止计算时溢出
        if (isBadVersion(mid)) 
        {
            right = mid;  // 答案在区间 [left, mid] 中
        } 
        else 
        {
            left = mid + 1;  // 答案在区间 [mid+1, right] 中
        }
    }
    // 此时有 left == right,区间缩为一个点,即为答案
    return left;
}

3.35搜索插入位置

3.1题目链接

https://leetcode-cn.com/problems/search-insert-position/

3.2题目描述

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。

在这里插入图片描述

3.3题目分析

这其实也是二分法的运用。注意,题目要求是返回插入的位置,这也就是说,如果数字在数组中存在,我们就通过二分查找找到他的位置,如果不存在,我们也可以知道比它大和比它小的值,那么当它插入进去的时候比它大的第一个数的位置就是他插入后他的位置。

3.4代码实现

C语言

int searchInsert(int* nums, int numsSize, int target) 
{
	int left = 0, right = numsSize;

	while (left < right)
	{
		int mid = left + (right - left) / 2;

		if (nums[mid] >= target)
		{
			right = mid;
		}
		else
		{
			left = mid + 1;
		}
	}

	return left;
}

后记

好的,我们今天题海求知的博文就分享到这里啦。现在是2021年8月13日的凌晨两点,在写这篇博文的过程中我也在看英仙座流星雨的直播,目前还没有看到大片的流星雨,但是还是从直播中看到了一些分散的流星雨。
在这里插入图片描述
最开始我是在B站上看人民日报的直播,可是不久前却卡了。
在这里插入图片描述
在这里插入图片描述

于是转战央视新闻的直播啦。
在这里插入图片描述
老夜猫子的我现在还不打算睡,希望今晚可以如愿看到大片的流星雨,也觉得此时此刻还有很多人正在一起期盼这片星空是一件很美好的事情。大家看到这篇文章也在心里默默许一个愿望吧,也许会实现哦。祝我们都有好运,这篇博文先到这里,拜拜啦。

<think>嗯,用户之前问过如何提升Java开发水平,我给了他们一个比较全面的建议,包括LeetCode的部分。现在他们接着问“怎样LeetCode”,这说明他们可能已经开始关注算法和数据结构的学习,想要更具体的指导。用户可能是刚开始接触LeetCode,或者遇到了瓶颈,不知道怎么高效。 首先,我需要确定用户的需求到底是什么。他们可能想知道的方法论,比如应该按照什么顺序,如何平衡数量和质量,遇到难怎么办,或者如何利用LeetCode准备面试。考虑到之前提到的是Java开发,可能用户更倾向于用Java,所以需要强调语言的选择和熟练度。 接下来,我得考虑用户的水平。如果是初学者,可能需要从基础的数据结构开始,逐步深入。如果已经有基础,可能需要更高效的策略,比如高频目或专训练。根据用户之前的提问,他们可能处于中级阶段,正在寻求提升,所以应该兼顾基础和进阶方法。 然后,我需要整理LeetCode的有效步骤。常见的建议包括按类型分类、循序渐进、总结反思等。还要强调不要只追求数量,而是理解每个目的解法和优化思路。此外,模拟面试环境也很重要,特别是时间限制和沟通能力的培养。 可能用户没有意识到的是,不仅仅是写代码,还包括问分析、测试用例的考虑以及与他人讨论。所以需要提醒他们注意这些方面。另外,推荐一些资源,比如经典目列表、学习资料和社区,可以帮助他们更系统地学习。 最后,要给出鼓励的话语,强调坚持和正确方法的重要性。避免让用户感到压力,而是让他们有信心通过系统的方法逐步提升。同时,结合之前的建议,将作为提升Java开发能力的一部分,帮助他们全面成长。</think> LeetCode 是提升算法能力和面试竞争力的有效方法,但需要科学的策略才能事半功倍。以下是结合实战经验的系统化建议: --- ### **一、前期准备** 1. **语言选择** - **优先使用 Java**:巩固 Java 语法特性(如集合操作、Stream API),但需注意 Java 代码在 LeetCode 中的性能陷阱(如频繁自动装箱)。 - **熟悉数据结构 API**:如 `PriorityQueue`、`TreeMap`、`Arrays.sort()` 的定制排序写法。 2. **基础铺垫** - 掌握常见数据结构(数组、链表、栈、队列、哈希表、堆、树、图)。 - 理解基础算法二分查找、DFS/BFS、双指针、滑动窗口、动态规划、回溯)。 - 推荐书籍:《算法(第4版)》《剑指Offer》 --- ### **二、方法论** #### **1. 分阶段推进** - **第一阶段:按标签分类(2-3个月)** - 按 **算法类型** 集中(如连续一周专攻「动态规划」) - 推荐顺序:数组/字符串 → 链表 → 二叉树 → 回溯 → 动态规划 → 图论 → 设计 - 经典入门(示例): - 二叉树:[104. 最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) → [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/) - 动态规划:[70. 爬楼梯](https://leetcode.cn/problems/climbing-stairs/) → [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) - **第二阶段:高频 & 面试(1-2个月)** - 企业高频(如 [LeetCode 100](https://leetcode.cn/problem-list/2cktkvj/)) - 重点练习 **《剑指Offer》** 和 **《程序员面试金典》** 目 - **第三阶段:模拟面试(持续)** - 使用「随机库」功能,限时 30-45 分钟完成 - 尝试用白板/纯文本写代码(适应真实面试环境) #### **2. 技巧** - **五步法**: 1. 读后先自己思考,写下可能的解法(即使暴力解法) 2. 尝试写代码实现,记录遇到的边界问 3. 对比官方解,分析时间/空间复杂度差异 4. 隔重新手写代码(避免短期记忆欺骗) 5. 总结到笔记中(模板代码、易错点、同类规律) - **重点关注**: - 代码的 **鲁棒性**(处理空输入、边界值) - 时间复杂度优化(如从 O(n²) 到 O(n) 的跳跃) - 空间换时间的取舍(如哈希表缓存中间结果) #### **3. 避坑指南** - ❌ 盲目追求量(300系统化训练 > 1000随机) - ❌ 过早看解(至少思考 20 分钟再参考答案) - ❌ 忽略测试用例(要主动设计边缘 case,如超大输入、负数、空值) --- ### **三、Java 专项优化** 1. **性能调优** - 减少自动装箱:用 `int[]` 代替 `List<Integer>` - 字符串拼接:优先用 `StringBuilder` - 注意集合初始化容量(如 `new HashMap<>(n)` 避免扩容) 2. **工具方法模板** ```java // 快速输入(适用于算法竞赛) Scanner sc = new Scanner(System.in); // 自定义排序 Arrays.sort(arr, (a, b) -> a[0] - b[0]); // 二叉树定义 class TreeNode { int val; TreeNode left; TreeNode right; TreeNode() {} } ``` --- ### **四、辅助工具推荐** 1. **学习资源** - 可视化工具:[Data Structure Visualizations](https://www.cs.usfca.edu/~galles/visualization/Algorithms.html) - 解平台:LeetCode 官方解、[宫水三叶的解指南](https://leetcode.cn/u/ac_oier/) - 代码模板:[labuladong 的算法小抄](https://labuladong.github.io/algo/) 2. **效率工具** - 本地 IDE 调试:IntelliJ IDEA 的 LeetCode 插件 - 代码管理:用 Git 仓库记录每日(便于复盘) - 错本:Notion/Excel 记录每的耗时、错因、优化点 --- ### **五、高阶思维培养** - **从 AC 到举一反三**: 例如完 [15. 三数之和](https://leetcode.cn/problems/3sum/),可以延伸思考: - 如何扩展到「四数之和」? - 如果数组是链表结构该如何处理? - 如果要求输出索引而非具体数值,解法有何不同? - **系统设计思维**: 对设计类目(如 [146. LRU 缓存](https://leetcode.cn/problems/lru-cache/)),不仅要实现功能,还要: - 分析并发场景下的线程安全问 - 考虑分布式环境下如何扩展 --- ### **六、实战数据参考** - **面试通过率统计**(来源:LeetCode 2023 调研): - 200-300 :约 65% 通过率 - 300-500 + 专项训练:超过 85% 通过率 - 关键指标:**中等熟练度**(占大厂面试的 70% 以上) --- **坚持每日 2-3 + 深度总结**,3-6 个月后会有显著提升。记住:不是目的,而是培养**将问抽象为算法模型的能力**,这才是工程师的核心竞争力。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lxkeepcoding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值