LeetCode 2540. 最小公共值

LeetCode 2540. 最小公共值 - 题解教程

1. 题目链接与难度

2540. 最小公共值 | 难度:简单

  • 题目类型:数组、双指针
  • 核心考点:利用有序特性优化查找

2. 白话题意重述

想象你手里有两叠已经按从小到大排好序的卡片:

  • 第一叠卡片:nums1 = [1, 2, 3]
  • 第二叠卡片:nums2 = [2, 4]

你的任务是:找出这两叠卡片中,同时出现在两叠里的最小数字

如果两个数组没有共同的数字,就返回 -1

💡 关键点

  • 两叠卡片都已经按"非降序"排好了(就是从小到大,允许重复)
  • "公共"的意思是:这个数字在两个数组中都至少出现一次
  • 要找的是"最小"的公共值

3. 解法全景与决策

3.1 直观暴力解法

最自然的想法是:先记录第一个数组里有哪些数字,然后检查第二个数组

具体步骤:

  1. nums1 的所有数字放进一个"备忘录"(比如哈希表)
  2. 遍历 nums2,找出所有同时出现在"备忘录"里的数字
  3. 从这些公共数字中,挑出最小的那个

手动模拟

复制代码
nums1 = [1, 2, 3], nums2 = [2, 4]

Step 1: 记录 nums1 的所有数字
备忘录 = {1, 2, 3}

Step 2: 遍历 nums2
- 看到 2:2 在备忘录里!记录 2
- 看到 4:4 不在备忘录里,跳过

Step 3: 公共数字有 [2],最小的就是 2

代码思路(Python)

python 复制代码
def getCommon(nums1, nums2):
    seen = set(nums1)  # 放进备忘录
    common = []
    for num in nums2:
        if num in seen:
            common.append(num)
    return min(common) if common else -1

3.2 空间优化的契机

哈希表解法的时间复杂度是 O(m + n)------这已经是最优的了,因为每个元素至少要被看一次,不可能更快。

但是 ,我们来分析一下空间开销:哈希表需要额外存储 nums1 中的所有元素,空间复杂度是 O(m)

🤔 一个自然的问题产生了:如果面试官问"能不能用 O(1) 空间来实现?",我们该怎么办?

回想一下这道题给我们的额外信息 :两个数组都是有序的。这个信息我们还没用上!


3.3 核心优化思路

关键洞察 :既然两个数组都是有序的,我们可以不用哈希表,直接用双指针"同步遍历"。

为什么有序就能不用哈希表?

在哈希表解法中,我们需要哈希表来"快速判断":nums2[j] 是否在 nums1 中出现过。这本质上是一个"查找"操作。

但如果两个数组都是有序的,查找可以更简单------我们让两个指针对齐着走,而不是用额外的空间来存储"我已经看过什么"。

生活类比

想象你和朋友各拿着一本按拼音排序的通讯录,你们想找出共同的好友。

哈希表做法:你把你的通讯录全部背下来(O(m) 空间),然后一个个问朋友"这个人在不在你的本子里?"

对齐做法:你们同时翻开第一页,比较这两个名字:

  • 如果你的名字排在前面,说明"你的朋友"不太可能出现在朋友那本的后半部分(拼音更靠后),所以你翻到下一页
  • 如果朋友的名字排在前面,同理,朋友翻到下一页
  • 如果恰好一样,bingo!这就是共同好友,而且一定是拼音最靠前的那个

为什么这能工作?

  • nums1[i] < nums2[j] 时,nums1[i] 不可能和 nums2[j] 或它后面的任何元素相等(因为 nums2 是递增的)
  • 所以我们可以安心地跳过 nums1[i],继续比较 nums1[i+1]nums2[j]
  • 反之亦然

ASCII 图示

复制代码
初始状态:
nums1 = [1, 2, 3]
          ↑
         i=0

nums2 = [2, 4]
          ↑
         j=0

比较 nums1[0]=1 和 nums2[0]=2
1 < 2,说明 1 不可能是公共元素(因为 nums2[0] 已经是 2 了,nums2 后面只有更大的数)
所以移动 i:

nums1 = [1, 2, 3]
             ↑
            i=1

nums2 = [2, 4]
          ↑
         j=0

比较 nums1[1]=2 和 nums2[0]=2
相等!找到公共元素,返回 2

核心思想:不需要"记忆"已经看过什么,只需要"对齐着走",利用有序性保证我们不会错过任何可能的公共元素。


4. 代码实现

理解了上面的思路后,代码就很好写了:

python 复制代码
class Solution:
    def getCommon(self, nums1: List[int], nums2: List[int]) -> int:
        # 双指针分别指向两个数组的起始位置
        i, j = 0, 0
        
        # 同时遍历两个数组
        while i < len(nums1) and j < len(nums2):
            if nums1[i] == nums2[j]:
                # 找到公共元素,直接返回(因为数组有序,这是最小的)
                return nums1[i]
            elif nums1[i] < nums2[j]:
                # nums1 的当前元素更小,移动 i 指针
                i += 1
            else:
                # nums2 的当前元素更小,移动 j 指针
                j += 1
        
        # 遍历结束还没找到公共元素
        return -1

代码解释

  1. 初始化双指针i 指向 nums1 的开头,j 指向 nums2 的开头
  2. 比较并移动
    • 如果 nums1[i] == nums2[j],找到了!直接返回(因为数组有序,第一个找到的就是最小的)
    • 如果 nums1[i] < nums2[j],说明 nums1[i] 太小了,不可能再和 nums2[j] 后面的元素匹配,所以 i += 1
    • 反之,j += 1
  3. 遍历结束 :如果 while 循环结束还没返回,说明没有公共元素,返回 -1

复杂度分析

  • 时间复杂度 :O(m + n),其中 m 和 n 分别是两个数组的长度。每个指针最多移动 m 和 n 步。
    • 通俗解释:当 m = 1万,n = 1万时,最多进行 2万 次比较,完全没问题
  • 空间复杂度:O(1),只用了两个指针变量,不需要额外的数据结构

5. 易错点与防坑指南

易错点 1:忘记处理"没有公共元素"的情况

错误示例

python 复制代码
def getCommon(nums1, nums2):
    i, j = 0, 0
    while i < len(nums1) and j < len(nums2):
        if nums1[i] == nums2[j]:
            return nums1[i]
        elif nums1[i] < nums2[j]:
            i += 1
        else:
            j += 1()

问题 :如果循环结束还没找到公共元素,函数会默认返回 None ,但题目要求返回 -1

正确做法 :在 while 循环后显式返回 -1

易错点 2:误以为需要找到"所有"公共元素再取最小值

一个很自然的尝试是

"我得先找到所有公共元素,然后再用 min() 找最小的。"

为什么这是多余的?

因为两个数组都是有序的 !当我们第一次找到 nums1[i] == nums2[j] 时,这个元素一定是最小的公共元素。

证明

  • 假设存在更小的公共元素 x,且 x < nums1[i]
  • 因为 nums1 是有序的,x 一定在 nums1[i] 的前面
  • 但我们的 i 指针是从头开始移动的,如果 xnums1 中存在,我们不可能跳过它
  • 矛盾!所以第一次找到的公共元素就是最小的

启示:不需要找"所有"公共元素,找到第一个就可以直接返回了。


6. 思考题与同类扩展

思考题

变体问题 :如果两个数组是降序排序的,你会怎么调整代码?
点击查看思路提示

可以从数组的末尾开始遍历(双指针初始化为 i = len(nums1) - 1, j = len(nums2) - 1),比较逻辑类似,但移动方向相反。

同类题目推荐

  1. 349. 两个数组的交集

    • 推荐理由:同样的"两个数组+公共元素"问题,但这次要找出所有公共元素(不重复)。可以用哈希表或双指针。
  2. 392. 判断子序列

    • 推荐理由:同样利用双指针在一个有序(或按某种顺序)的结构中高效匹配,是双指针技巧的经典应用。

总结 :这道题的核心在于利用有序特性,用双指针实现 O(m + n) 时间、O(1) 空间的优雅解法。下次遇到"两个有序数组"的问题,记得先想想双指针!

相关推荐
小许同学记录成长9 小时前
轻量正射实现原理技术文档
算法·无人机
阿文的代码库9 小时前
如何在C++中使用标准库的智能指针
开发语言·c++·算法
城事漫游Molly9 小时前
方差分析(ANOVA)入门——比较三组或更多组均值的利器
大数据·算法·均值算法·论文笔记·科研统计
一只机电自动化菜鸟9 小时前
一建机电备考笔记(38) 焊接技术—焊接质量检验(含考频+题型)
笔记·学习·职场和发展·生活·学习方法
Yzzz-F9 小时前
[专题]最大子矩形问题
算法
WL_Aurora9 小时前
Python 算法基础篇之查找算法(三):树表查找
python·算法
吃好睡好便好9 小时前
在Matlab中绘制二维直方图
开发语言·人工智能·学习·算法·matlab
温九味闻醉9 小时前
关于腾讯广告算法大赛2025项目面试要点
人工智能·算法·机器学习
sheeta19989 小时前
LeetCode 每日一题笔记 日期:2026.05.15 题目:153. 寻找旋转排序数组中的最小值
笔记·算法·leetcode