近日,一则题为“Making sure pairs of integers are contained in a list”(确保整数对包含在列表中)的编程问题在国内外开发者社区引发热议。该问题最初出现在某知名技术问答平台,短短数日便收获数十种解法,讨论焦点从最基础的暴力遍历一路延伸至哈希优化、排序预处理乃至图论建模,堪称算法入门与实际工程需求结合的经典案例。
问题缘起:如何理解“包含”?
问题的原始描述并不复杂:给定一个整数列表(例如 [3, 5, 7, 9, 11])以及若干整数对(例如 (3, 5)、(7, 11)),要求判断每一对整数是否都“包含”在列表中。但“包含”一词存在两种自然解读:其一,只要两个整数各自出现在列表里即可视为包含,不关心它们在列表中的相对位置;其二,则要求两个整数在列表中必须连续出现,形成相邻的“对”。这两种解释导致完全不同的算法路径,也让讨论迅速升温。
朴素解法:清晰但低效
多数初学者首先想到的是遍历每一个整数对,对每个元素再遍历整个列表进行查找。假设列表长度为 n,整数对数量为 m,则最坏情况下时间复杂度为 O(n×m)。当列表规模达到百万级、待检对达到十万级时,运算量将膨胀至千亿次级别,在实时系统中几乎不可接受。更糟的是,如果采用连续子序列的严格定义,还需额外记录位置信息,代码复杂度亦随之上升。
高效解法:哈希集合的妙用
在众多讨论中,最受推崇的方案是利用哈希集合(Hash Set)将列表元素预处理存储。具体做法为:先遍历一次整数列表,将所有元素放入一个无序集合中,此后每个整数对的检查便只需两次 O(1) 的哈希查找。整体时间复杂度由 O(n×m) 降至 O(n+m),空间复杂度为 O(n) 用于存储集合。
一位署名“代码旅人”的开发者给出了 Python 实现片段:
def ensure_pairs_in_list(lst, pairs):
elements = set(lst)
return all(a in elements and b in elements for a, b in pairs)
该代码简洁直观,迅速获得大量点赞。评论区指出,此方法还能天然过滤重复元素,且对列表顺序不作假设,适用于大多数业务场景。
深入探讨:若要求“相邻”呢?
若问题中的“包含”被严格解释为“两个整数在列表中必须连续出现”,则解法需彻底改变。此时可利用字典记录每个元素最后一次出现的位置,然后遍历列表,对相邻两数构成的有序对建立“已出现”标记。或者更进一步,将列表转化为边集构建图结构,再利用并查集或邻接表进行批量查询。有参与者指出,这种变体与“给定图中是否存在某条边”的问题同构,可用哈希集合存储所有长度为 2 的连续子序列,同样能达到近常数时间查询。
工程意义:不止于刷题
这一问题的价值远超面试题范畴。在数据清洗中,需要验证关联表中引用的外键是否均在主键清单内;在配置管理里,需确认依赖列表中每一对服务名是否都已注册;在实时交易系统,需检查买卖双方的账户 ID 是否存在于可信账户集合中。凡此种种,本质都是“判断一组对是否包含于一个集合”。选择合适的数据结构,直接决定了系统的吞吐量与延迟。
结语:小问题,大智慧
一个看似直白的整数对包含检查,折射出算法设计中对“输入规模”“语义定义”和“操作成本”的权衡。正如一位参与者总结:“简单问题不简单,关键是定义清楚问题,再选择匹配的工具。”无论是哈希集合的巧妙降维,还是对连续对定义的重新建模,都提醒开发者:在动手写循环之前,不妨先问问自己——问题的真正约束是什么?这或许正是该帖子持续被大量转发的原因所在。