高效比较有序列表并统计常见元素(包括重复元素)

60 阅读4分钟
a = [2, 3, 3, 4, 4, 5]
b1 = [0, 2, 2, 3, 3, 4, 6, 8]

我们需要统计列表 a 中元素在列表 b1 中出现的次数,其中重复元素也需要计算在内。

2、解决方案

为了解决这个问题,我们可以使用多种方法。以下是一些常用的解决方案:

(1)使用集合交集运算

我们可以使用 Python 的 collections.Counter 类来计算两个列表的并集和交集。交集操作可以帮助我们快速找到两个列表中相同的元素,而并集操作可以帮助我们统计重复元素出现的次数。

import collections

def common_elements(list1, list2):
    # 初始化两个 Counter 对象,分别统计列表1和列表2中元素出现的次数
    counter1 = collections.Counter(list1)
    counter2 = collections.Counter(list2)

    # 计算并集
    union = counter1 + counter2

    # 计算交集
    intersection = counter1 & counter2

    # 统计交集中每个元素出现的次数
    common_counts = [union[key] for key in intersection]

    # 返回交集中所有元素出现的次数之和
    return sum(common_counts)

(2)使用双指针法

双指针法是一种比较两个有序列表的常用算法。我们可以使用两个指针,分别指向两个列表的第一个元素。然后,我们可以同时遍历两个列表,比较两个指针指向的元素。如果两个元素相等,则将它们标记为相同元素,并分别将两个指针指向下一个元素。如果两个元素不相等,则将指针指向较小的元素。

def common_elements(list1, list2):
    # 初始化两个指针,分别指向列表1和列表2的第一个元素
    i = 0
    j = 0

    # 统计相同元素出现的次数
    common_count = 0

    # 循环遍历两个列表
    while i < len(list1) and j < len(list2):
        # 如果两个指针指向的元素相等
        if list1[i] == list2[j]:
            # 统计相同元素出现的次数
            common_count += 1

            # 将两个指针指向下一个元素
            i += 1
            j += 1
        # 如果列表1的元素较大
        elif list1[i] > list2[j]:
            # 将指针j指向下一个元素
            j += 1
        # 如果列表2的元素较大
        else:
            # 将指针i指向下一个元素
            i += 1

    # 返回相同元素出现的次数
    return common_count

(3)使用 Counter 类和排序后的列表

如果两个列表都经过排序,我们可以使用 collections.Counter 类来统计列表1中元素在列表2中出现的次数。具体步骤如下:

  1. 将列表2转换为 collections.Counter 对象,以便快速查找元素出现的次数。
  2. 遍历列表1,对于每个元素,查找其在列表2中的出现次数,并将其添加到统计结果中。
import collections

def common_elements(list1, list2):
    # 将列表2转换为 Counter 对象
    counter = collections.Counter(list2)

    # 统计列表1中元素在列表2中出现的次数
    common_counts = [counter[element] for element in list1]

    # 返回列表1中元素在列表2中出现的次数之和
    return sum(common_counts)

(4)使用二分查找法

如果列表2非常长,我们可以使用二分查找法来快速查找列表1中元素在列表2中出现的次数。具体步骤如下:

  1. 对于列表1中的每个元素,使用二分查找法在列表2中查找其出现的位置。
  2. 如果找到该元素,则统计其出现的次数。
  3. 如果没有找到该元素,则将其标记为不存在。
def common_elements(list1, list2):
    # 统计相同元素出现的次数
    common_count = 0

    # 对于列表1中的每个元素
    for element in list1:
        # 使用二分查找法在列表2中查找其出现的位置
        index = binary_search(element, list2)

        # 如果找到该元素
        if index != -1:
            # 统计相同元素出现的次数
            common_count += 1

    # 返回相同元素出现的次数
    return common_count


def binary_search(element, list2):
    # 设置左右边界
    left = 0
    right = len(list2) - 1

    # 循环搜索
    while left <= right:
        # 计算中间位置
        mid = (left + right) // 2

        # 如果中间位置的元素等于要查找的元素
        if list2[mid] == element:
            # 返回中间位置
            return mid
        # 如果中间位置的元素大于要查找的元素
        elif list2[mid] > element:
            # 将右边界设置为中间位置的前一个位置
            right = mid - 1
        # 如果中间位置的元素小于要查找的元素
        else:
            # 将左边界设置为中间位置的后一个位置
            left = mid + 1

    # 如果没有找到该元素
    return -1