【问题标题】:Finding the Unique Elements Among n Arrays在 n 个数组中查找唯一元素
【发布时间】:2013-11-02 02:09:07
【问题描述】:

我正在尝试编写一个算法,该算法采用可变数量的通用数组,存储在d_arrays 中,并收集其中所有唯一元素(仅出现一次的元素)并将它们存储在一个数组中,称为 @ 987654322@。例如数组:

int intA[] = { 12, 54, 42 };
int intB[] = { 54, 3, 42, 7 };
int intC[] = { 3, 42, 54, 57, 3 };

将生成数组d_results,内容为{ 12, 7, 57 }。

这是我目前的流程算法:

template <class T>
inline
void UniqueTableau<T>::run() {
    T* uniqueElements = d_arrays[0];
    int count = 0;
    for (int i = 1; i < d_currentNumberOfArrays; ++i) {
        if (count == 0) {
            uniqueElements = getUnique(uniqueElements, d_arrays[i], d_sizes[i - 1], d_sizes[i]);
            ++count;
        }
        else {
            uniqueElements = getUnique(uniqueElements, d_arrays[i], d_numberOfElementsInResult, d_sizes[i]);
        }
    }
    d_results = uniqueElements;
}

template <class T>
inline
T* UniqueTableau<T>::getUnique(T* first, T* second, int sizeOfFirst, int sizeOfSecond) {
    int i = 0;
    int j = 0;
    int k = 0;
    T* uniqueElements = new T[sizeOfFirst + sizeOfSecond];
    while (i < sizeOfFirst) {    // checks the first against the second
        while ((first[i] != second[j]) && (j < sizeOfSecond)) {
            ++j;
        }
        if (j == sizeOfSecond) {
            uniqueElements[k] = first[i];
            ++i;
            ++k;
            j = 0;
        } else {
            ++i;
            j = 0;
        }
    }
    i = 0;
    j = 0;
    while (i < sizeOfSecond) {    // checks the second against the first
        while ((second[i] != first[j]) && (j < sizeOfFirst)) {
            ++j;
        }
        if (j == sizeOfFirst) {
            uniqueElements[k] = second[i];
            ++i;
            ++k;
            j = 0;
        } else {
            ++i;
            j = 0;
        }
    }

    T* a = new T[k];    // properly sized result array
    for (int x = 0; x < k; ++x) {
        a[x] = uniqueElements[x];
    }

    d_numberOfElementsInResult = k;
    return a;
}

请注意,d_sizes 是一个数组,其中包含 d_arrays 中每个数组的大小,d_numberOfElementsInResult 是 d_results 中的元素数。

现在,这个数组所做的是一次比较两个,获取这两个之间的唯一元素,并将这些元素与下一个数组进行比较,等等。问题是,当我这样做时,有时会有一些元素在第三个数组和前两个数组的唯一元素之间是唯一的,但在第三个和第一个数组之间不是唯一的。这是一个令人困惑的措辞,所以这是一个使用上面的数组的视觉示例:

首先,算法找到第一个和第二个数组的唯一元素。

{ 12, 3, 7 }

现在,它会根据第三个数组检查它,在它们之间生成唯一元素。

{ 12, 7, 42, 54, 57 }

对吗?错误的。这里的问题是,由于42 和54 没有出现在唯一数组中,它们最终会出现在最终产品中,即使它们对所有三个数组都是通用的。

谁能想到一个解决方案?对此算法进行修改是首选,但如果这不可能,还有什么方法可以解决这个问题?

【问题讨论】:

  • 为什么不把所有数组中的所有元素都放在一个 singke 数组中,对其进行排序,然后进行线性跟踪以检查是否有重复。
  • 这不是最聪明的,也可能不是最高效的解决方案,但我只是将所有数组转储到一个计数字典中,以整数为键(例如 54 在所有三个数组中所以(54, 3) 将在处理完所有数组后出现在您的字典中)。最后,只需遍历桶,只抓取计数为 1 的桶。
  • @roliu 这正是我在回答中所建议的。

标签: c++ arrays algorithm unique


【解决方案1】:

编辑:正如所指出的,该算法的时间复杂度为 O(nlogn),空间复杂度为 O(n)。

对所有数组中的每个元素进行一次遍历,并形成每个遍历项的计数的映射。

创建地图后,只需遍历它并形成计数为 1 的元素的数组。

【讨论】:

  • 对于 std::map 来说不是 O(n) 时间 - 插入 std::map 是 O(log n)。使用带有摊销常数时间插入的 std::unordered_map 会给你 O(n)。
  • 对不起,我不熟悉std::map。如果我要这样做,键会是元素的计数吗?或者我会将 Key 设为元素并将其值设为计数?谢谢。
  • @Will Yes 键是元素,值是计数。
【解决方案2】:

内存是问题,虽然我会以不同的方式来做这件事(由于缺乏经验?)——实际上我正在考虑刚刚发布的答案!

无论如何,请不要丢弃重复项并将它们保存在辅助数组中。获取这个数组并将其附加到每个新数组两次,这将使您的算法几乎没有变化。唯一的变化是创建重复项并每次查看更大的列表。虽然这增加了时间和记忆。如果这是一个问题,那么请使用第一个发布的答案!

【讨论】:

    【解决方案3】:

    解决方案 1:

    1. 只需将所有数组的所有元素合二为一即可。
    2. 对数组进行排序
    3. 删除重复项。

    解决方案 2:

    1. 创建一个映射,其中键是元素,值是布尔值
    2. 只遍历单个数组。如果该元素不存在于地图中,则将键作为元素,将值作为真。但如果该元素已经存在,则将该值设为 false。
    3. 现在只需打印地图中值部分为真的元素,即只出现一次。

    为什么我将值作为布尔值而不是整数:

    我们知道,如果地图中存在键形式的元素,则表明该元素存在于数组中。因此,如果我们下次再次找到该元素时将其设为 false,则它会显示重复。希望你能理解。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-07
      • 1970-01-01
      • 2013-02-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多