一句话说透数据结构里面的两个有限List求相同元素,如果是两个无限List呢?

211 阅读2分钟

一、有限 List 求交集

解决方案:  使用集合(Set)快速查找,时间复杂度 O(n + m)

// 有限 List 求交集(去重)
fun findCommonElements(list1: List<Int>, list2: List<Int>): Set<Int> {
    val set1 = list1.toSet()
    val set2 = list2.toSet()
    return set1 intersect set2
}

// 保留重复元素的最小次数(例如 list1=[2,2,3], list2=[2,2,2] → 返回 [2,2])
fun findCommonElementsWithDuplicates(list1: List<Int>, list2: List<Int>): List<Int> {
    val countMap1 = list1.groupingBy { it }.eachCount()
    val countMap2 = list2.groupingBy { it }.eachCount()
    return countMap1.flatMap { (num, count1) ->
        val count2 = countMap2[num] ?: 0
        List(min(count1, count2)) { num }
    }
}

测试用例:

fun main() {
    // 测试去重版本
    val listA = listOf(1, 2, 2, 3)
    val listB = listOf(2, 2, 4)
    println(findCommonElements(listA, listB)) // 输出 [2]

    // 测试保留重复版本
    println(findCommonElementsWithDuplicates(listA, listB)) // 输出 [2, 2]
}

二、无限 List 求交集

假设条件:  两个无限 List 必须是有序的(如递增),否则无法有效求解!
解决方案:  双指针法逐步生成元素并比较,时间复杂度 O(k)(k 为找到的交集元素数量)

// 生成无限递增序列(示例1:自然数;示例2:平方数)
fun infiniteSequence1(): Sequence<Int> = generateSequence(0) { it + 1 }
fun infiniteSequence2(): Sequence<Int> = generateSequence(0) { (it + 1) * (it + 1) }

// 双指针法求交集(要求两个序列递增)
fun findCommonInfiniteElements(seq1: Sequence<Int>, seq2: Sequence<Int>): Sequence<Int> = sequence {
    val iterator1 = seq1.iterator()
    val iterator2 = seq2.iterator()
    
    if (!iterator1.hasNext() || !iterator2.hasNext()) return@sequence
    
    var a = iterator1.next()
    var b = iterator2.next()
    
    while (true) {
        when {
            a == b -> {
                yield(a)
                a = iterator1.next()
                b = iterator2.next()
            }
            a < b -> a = iterator1.next()
            else -> b = iterator2.next()
        }
    }
}

测试用例:

fun main() {
    // 生成两个无限序列的交集(自然数 vs 平方数,交集为 0,1,4,9,16,...)
    val common = findCommonInfiniteElements(infiniteSequence1(), infiniteSequence2())
    
    // 取前5个交集元素测试
    println(common.take(5).toList()) // 输出 [0, 1, 4, 9, 16]
}

三、复杂度分析

场景时间复杂度空间复杂度
有限 List 去重O(n + m)O(n + m)
无限 List 有序O(k)(k为实际找到的元素数)O(1)

四、关键点总结

  1. 有限 List

    • 去重用 Set,保留重复次数用 计数哈希表
    • 示例:[1,2,2,3] 和 [2,2,4] 的交集为 [2] 或 [2,2]
  2. 无限 List

    • 必须有序(如递增),否则无法高效求解
    • 使用 generateSequence 生成无限流,双指针逐步比较
  3. 注意事项

    • 无限流处理需设置终止条件(如 take(5) 取前几个元素)
    • 若无限流无序,只能通过哈希表处理,但内存会无限增长(不可行)

口诀:
有限列表用集合,
无限有序双指针。
无序无限无解药,
内存爆炸要记牢!