1. 概述

在本教程中,我们将讨论如何从一个包含 2N 只袜子的数组中高效地配对出 N 对袜子。

首先我们会明确问题,并通过一个例子进行说明。接着会介绍一个朴素解法,然后提出两种优化方案,分别是排序法和哈希法。

2. 问题定义

假设我们有一个长度为 2N 的数组,其中包含 N 对袜子。每只袜子可能有多个属性,如颜色、尺码等。我们的任务是将这些袜子按照属性配对。

举个例子来帮助理解:

我们有一个包含 8 只袜子的数组,每只袜子都有颜色和尺码属性:

袜子示例

图中每个格子的颜色代表袜子的颜色,数字代表尺码。我们需要将相同颜色和尺码的袜子配对:

配对结果

本教程仅讨论找到一种可行的配对方式,不考虑存在多个解的情况。

3. 朴素解法

3.1. 核心思路

遍历数组,对每只未配对的袜子,再次遍历数组寻找匹配项。

3.2. 实现代码

algorithm findSimilarPairsNaive(N, sock):
    // INPUT
    //    N = the number of pairs of socks
    //    sock = the array that represents the socks
    // OUTPUT
    //    Returns similar pairs of socks in sock
    
    answer <- an empty sequence
    taken <- an array of false, with length 2 * N
    
    for i <- 0 to 2 * N - 1:
        if taken[i] is true:
            continue
    
        taken[i] <- true
    
        for j <- i + 1 to 2 * N - 1:
            if sock[i] = sock[j]:
                answer <- add (sock[i], sock[j]) to answer
                taken[j] <- true
                break

    return answer

我们维护一个 taken 数组来记录每只袜子是否已被配对。外层循环遍历每个元素,内层循环查找匹配项。

3.3. 时间复杂度分析

时间复杂度为 **O(N²)**。

外层循环遍历 2N 个元素,内层循环平均查找 N 次。总操作数约为 N * N = N²

4. 排序法

4.1. 核心思路

先对袜子数组进行排序。这样相同属性的袜子就会相邻,只需一次遍历即可完成配对。

4.2. 实现代码

algorithm findSimilarPairsSorting(N, sock):
    // INPUT
    //    N = the number of pairs of socks
    //    sock = the array that represents the socks
    // OUTPUT
    //    Returns similar pairs of socks in sock

    answer <- an empty sequence
    sorted <- sort(sock)

    i <- 0
    while i <= 2 * N - 2:
        if sorted[i] = sorted[i + 1]:
            answer <- add (sorted[i], sorted[i + 1]) to answer
            i <- i + 1
        i <- i + 1

    return answer

先对数组排序,然后依次检查相邻元素是否相同。

4.3. 时间复杂度分析

时间复杂度为 **O(N log N)**。

排序时间复杂度是 O(N log N),遍历为 O(N),因此整体复杂度由排序决定。

5. 哈希法

5.1. 核心思路

使用 HashSet 记录已经遍历过的袜子。当遇到相同属性的袜子时,配对并移除。

5.2. 实现代码

algorithm findSimilarPairsHash(N, sock):
    // INPUT
    //    N = the Number of pairs of socks
    //    sock = the array that represents the socks
    // OUTPUT
    //    Returns similar pairs of socks in sock

    answer <- an empty sequence
    hash_set <- create an empty hash set

    i <- 0
    while i < 2 * N:
        if hash_set contains sock[i]:
            answer <- add (sock[i], hash_set.get(sock[i])) to answer
            hash_set.delete(sock[i])
        else:
            hash_set.add(sock[i])
        i <- i + 1

    return answer

使用 HashSet 存储已遇到的袜子。如果当前袜子已经在集合中,则配对成功并移除;否则加入集合。

5.3. 时间复杂度分析

时间复杂度为 **O(N)**。

我们遍历数组一次,每次操作(查找、添加、删除)的时间复杂度都是 O(1)。

6. 总结

本文讨论了三种解决袜子配对问题的方法:

方法 时间复杂度 说明
✅ 朴素法 O(N²) 简单直观但效率低,适合小数据集
✅ 排序法 O(N log N) 性能较好,适合中等规模数据
✅ 哈希法 O(N) 性能最佳,推荐使用

如果你追求效率,哈希法是首选方案。它在时间复杂度上最优,实现也相对简单。


原始标题:Pairing Socks From a Pile Efficiently