在O(n)中排序相交

时间:2016-09-12 06:30:48

标签: algorithm sorting time-complexity hashset

  
      
  • S1S2成为两组整数(它们不一定是不相交的)。
  •   
  • 我们知道   那个|S1| = |S2| = n(即每个集合都有n个整数)。
  •   
  • 每个集合都存储在长度为n的数组中,其中   它的整数按升序排序。
  •   
  • k ≥ 1为整数。
  •   
  • 设计算法以找到   O(n)时间kS1 ∩ S2个最小整数。
  •   

这是我到目前为止所做的:

  1. 创建一个名为Intersection
  2. 的新数组
  3. 对于e中的每个S1,在O(n)时间内将e添加到hashset
  4. 对于e中的每个S2,检查哈希集中是否存在e 时间
  5. 如果hashset中存在e,请将e添加到Intersection
  6. 按比例排序Intersection按排序在O(n)时间
  7. 进行排序
  8. 返回第一个k整数
  9. 因此,O(n)+ O(n)+ O(n)= O(n)

    我是在正确的轨道上吗?

3 个答案:

答案 0 :(得分:4)

是的,你肯定是在正确的轨道上,但实际上根本不需要生成哈希表或额外的集合。由于你的两个集合已经排序,你可以简单地通过两个集合运行索引/指针,寻找公共元素。

例如,要查找两个集合中的第一个公共元素,请使用以下伪代码:

start at first index of both sets
while more elements in both sets, and current values are different:
    if set1 value is less than set2 value:
        advance set1 index
    else
        advance set2 index

最后,set1 index将引用一个交叉点,前提是这两个索引都没有超出其各自列表中的最后一个元素。然后,您可以在循环中使用该方法来查找第一个x交集值。

这是Python 3中的概念证明,它为您提供了两个列表中的前三个数字(2的倍数和3的倍数)。完整的交集将是{0, 6, 12, 18, 24},但您会看到它只会提取前三个:

# Create the two lists to be used for intersection.

set1 = [i * 2 for i in range(15)] ; print(set1) # doubles
set2 = [i * 3 for i in range(15)] ; print(set2) # trebles

idx1 = 0 ; count1 = len(set1)
idx2 = 0 ; count2 = len(set2)

# Only want first three.

need = 3
while need > 0:
    # Continue until we find next intersect or end of a list.

    while idx1 < count1 and idx2 < count2 and set1[idx1] != set2[idx2]:
        # Advance pointer of list with lowest value.

        if set1[idx1] < set2[idx2]:
            idx1 += 1
        else:
            idx2 += 1

    # Break if reached end of a list with no intersect.

    if idx1 >= count1 or idx2 >= count2:
        break

    # Otherwise print intersect and advance to next list candidate.

    print(set1[idx1]) ; need -= 1
    idx1 += 1 ; idx2 += 1

正如预期的那样输出:

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42]
0
6
12

如果你最后需要一个列表而不是只打印出交叉点,你只需在循环之前初始化一个空容器,然后将值附加到它而不是打印它。这会变得更像您提出的解决方案,但具有不需要哈希表或排序的优势。

答案 1 :(得分:0)

创建两个数组,调用大小为arr1的{​​{1}}和arr2,并按整数值按升序填充它们。创建两个索引,称为array_sizei,分别用于迭代jarr1并将它们初始化为0.比较每个索引的前两个值数组:如果arr2小于arr1[0],则增加arr2[0],否则i大于arr1[0]增量arr2[0],否则值相交我们可以返回这个值。一旦我们返回k个相交值,我们就可以停止迭代了。在最坏的情况下,如果两组值之间没有交叉,那么这将是i + j,O(n),我们将不得不迭代到每个数组的末尾。

以下是bash中的解决方案:

j

输出:

#!/bin/bash
#-------------------------------------------------------------------------------
# Design an algorithm to find the k smallest integers in S1 ∩ S2 in O(n) time.
#-------------------------------------------------------------------------------

typeset -a arr1 arr2 arr_answer
typeset -i array_size=20 k=5

function populate_arrs {
    typeset -i counter=0

    while [[ ${counter} -lt ${array_size} ]]; do
        arr1[${counter}]=$((${counter} * 2))
        arr2[${counter}]=$((${counter} * 3))

        counter=${counter}+1
    done

    printf "%8s" "Set1: "; printf "%4d" ${arr1[*]}; printf "\n"
    printf "%8s" "Set2: "; printf "%4d" ${arr2[*]}; printf "\n\n"
}


function k_smallest_integers_main {
    populate_arrs

    typeset -i counter=0 i=0 j=0
    while [[ ${counter} -lt ${k} ]]; do
        if [[ ${arr1[${i}]} -eq ${arr2[${j}]} ]]; then
            arr_answer[${counter}]=${arr1[${i}]}
            counter=${counter}+1; i=${i}+1; j=${j}+1
        elif [[ ${arr1[${i}]} -lt ${arr2[${j}]} ]]; then
            i=${i}+1
        else
            j=${j}+1
        fi
    done

    printf "%8s" "Answer: "; printf "%4d" ${arr_answer[*]}; printf "\n"
}

k_smallest_integers_main

答案 2 :(得分:-2)

在Python中:

i1= 0; i2= 0
while k > 0 and i1 < n and i2 < n:
    if S1[i1] < S2[i2]:
        i1+= 1
    elif S1[i1] > S2[i2]:
        i2+= 1
    else:
        Process(S1[i1], S2[i2])
        i1+= 1; i2+= 1
        k-= 1

如果交叉点中没有足够多的元素,执行将对k的{​​{1}}次调用执行次数。