作为一个热爱编程的人,我一直对算法题有着浓厚的兴趣。最近在简书上看到了一道非常有趣的题目——第 k 个缺失的正整数(LeetCode 1539)。这道题看似简单,实则充满了挑战,尤其是当你深入思考时,你会发现它背后隐藏着许多值得探讨的内容。
题目描述如下:给你一个整数数组 arr,已知 arr 中每一个数都在 1 到 n 之间(含 1 和 n),n 为数组的长度。请你找出第 k 个缺失的正整数。
乍一看,这个问题似乎并不复杂,但当我真正动手去解时,才发现其中的奥妙。为了更好地理解这个问题,我决定从最基础的地方开始,逐步分析并优化解决方案。
一、初步思路:暴力解法
首先,我想到的是最直接的方法——暴力解法。我们可以创建一个从 1 开始的计数器,依次检查每个数字是否存在于数组中。如果某个数字不在数组中,我们就将其记录下来,并继续检查下一个数字,直到找到第 k 个缺失的正整数。
这个方法虽然简单易懂,但它的时间复杂度是 O(n * m),其中 n 是数组的长度,m 是我们遍历的次数。显然,这种方法在处理大规模数据时效率低下,无法满足实际应用的需求。
二、优化思路:使用哈希表
接下来,我尝试通过引入哈希表来优化解法。哈希表可以在常数时间内完成查找操作,因此可以大大提高效率。具体来说,我们可以先将数组中的所有元素存入哈希表,然后从 1 开始逐个检查是否存在,直到找到第 k 个缺失的正整数。
这个方法的时间复杂度是 O(n + m),其中 n 是数组的长度,m 是我们遍历的次数。相比暴力解法,这种方法已经大大提升了效率,但在某些情况下,仍然存在进一步优化的空间。
三、进一步优化:双指针法
经过一番思考,我发现了一个更巧妙的解法——双指针法。我们可以利用两个指针,一个指向当前正在检查的数字,另一个指向数组中的元素。通过比较这两个指针的值,我们可以快速找到缺失的正整数。
具体步骤如下:
- 初始化两个指针 i 和 j,分别指向 1 和数组的第一个元素。
- 遍历数组,比较 i 和 arr[j] 的值。
- 如果 i 不等于 arr[j],说明 i 是一个缺失的正整数,我们将 k 减 1。
- 如果 i 等于 arr[j],则将 j 向后移动一位,继续检查下一个元素。
- 当 k 为 0 时,返回 i 即可。
这个方法的时间复杂度是 O(n),并且不需要额外的空间,因此在时间和空间上都具有很大的优势。
四、实战演练:代码实现
理论分析固然重要,但真正的考验还是在于代码的实现。为了验证我的思路,我编写了以下 Python 代码:
def findKthPositive(arr, k):
i = 1 # 当前检查的数字
j = 0 # 数组中的指针
while k > 0:
if j < len(arr) and arr[j] == i:
j += 1 # 如果 i 存在于数组中,移动数组指针
else:
k -= 1 # 如果 i 不存在于数组中,k 减 1
if k == 0:
return i # 找到第 k 个缺失的正整数
i += 1 # 继续检查下一个数字
这段代码的核心思想就是通过双指针法,逐步缩小搜索范围,最终找到第 k 个缺失的正整数。经过多次测试,我发现这个算法不仅效率高,而且代码简洁易懂,非常适合初学者学习。
五、总结与反思
通过这次解题经历,我深刻体会到编程的魅力不仅仅在于解决问题,更在于如何用最优的方式去解决问题。每一道算法题都是一次挑战,而每一次挑战都让我对编程有了更深的理解。
在这个过程中,我也学到了很多宝贵的经验。首先,遇到问题时不要急于求成,而是要从最基础的地方入手,逐步分析,找到最优解。其次,算法的优化不仅仅是时间复杂度的提升,还包括空间复杂度的考虑。最后,编程是一项需要不断实践和总结的技能,只有通过不断的练习,才能真正掌握其中的精髓。
未来,我将继续探索更多有趣的算法题,不断提升自己的编程能力。我相信,只要保持对编程的热情,就一定能够在这个充满挑战的领域中取得更大的进步。
发表评论 取消回复