这段代码中的错误是什么?

时间:2011-07-17 15:06:17

标签: c arrays duplicate-removal

基于this逻辑作为对不同(类似)问题的SO的回答,为了在O(N)时间复杂度中删除数组中的重复数字,我在C中实现了该逻辑,如图所示下面。但是我的代码的结果不会返回唯一的数字。我试过调试,但无法得到它背后的逻辑来解决这个问题。

int remove_repeat(int *a, int n)
{
    int i, k;

    k = 0;
    for (i = 1; i < n; i++)
    {
        if (a[k] != a[i]) 
        {
            a[k+1] = a[i];
            k++;            
        }
    }
    return (k+1);
}

main()
{
    int a[] = {1, 4, 1, 2, 3, 3, 3, 1, 5};
    int n;
    int i;

    n = remove_repeat(a, 9);

    for (i = 0; i < n; i++)
            printf("a[%d] = %d\n", i, a[i]);


} 

1]上述代码中删除重复项的内容有误。

2]针对此问题的任何其他O(N)或O(NlogN)解决方案。它的逻辑?

7 个答案:

答案 0 :(得分:2)

  1. 在O(n log n)时间内排序。
  2. 在O(n)时间内迭代用哨兵值替换重复元素(例如INT_MAX)。
  3. 在O(n log n)中再次排序以蒸馏出重复元素。
  4. 仍以O(n log n)为界。

答案 1 :(得分:1)

您将需要两个循环,一个用于检查源,另一个用于检查目标数组中的每个项目。

会得到O(N)。

[编辑] 您链接的文章建议使用排序输出数组,这意味着在输出数组中搜索重复项可以是二进制搜索...即O(LogN)。

答案 2 :(得分:1)

您的代码似乎要求输入已排序。使用未分类的输入时,您的代码将不会删除所有重复项(仅限相邻项)。

答案 3 :(得分:1)

如果预先知道整数的数量并且小于你拥有的内存量,你就可以得到O(N)解决方案。使用辅助存储来确定一个唯一的整数,然后输出另一个以输出唯一值。

下面的代码是用Java编写的,但希望你能理解。

int[] removeRepeats(int[] a) {
    // Assume these are the integers between 0 and 1000
    Boolean[] v = new Boolean[1000]; // A lazy way of getting a tri-state var (false, true, null)

    for (int i=0;i<a.length;++i) {
       v[a[i]] = Boolean.TRUE;
    } 

    // v[i] = null => number not seen
    // v[i] = true => number seen

    int[] out = new int[a.length];
    int ptr = 0;
    for (int i=0;i<a.length;++i) {
        if (v[a[i]] != null && v[a[i]].equals(Boolean.TRUE)) {
            out[ptr++] = a[i];
            v[a[i]] = Boolean.FALSE;          
        }
    }

    // Out now doesn't contain duplicates, order is preserved and ptr represents how
    // many elements are set.
    return out;
}

答案 4 :(得分:1)

您的代码仅检查数组中的项是否与其前一个项相同。

如果您的数组开始排序,那将起作用,因为特定数字的所有实例都是连续的。

如果你的数组没有排序开始,那将无法工作,因为特定数字的实例可能不连续,所以你必须查看所有前面的数字以确定是否还有人看过。

要在O(N log N)时间内完成工作,您可以对数组进行排序,然后使用已有的逻辑从已排序的数组中删除重复项。显然,这只有在你重新安排数字时才有用。

如果您想保留原始订单,可以使用类似哈希表或位设置的内容来跟踪是否已经看到某个数字,并且当/它还没有时,只将每个数字复制到输出中被人看见了。为此,我们改变您的当前状态:

if (a[k] != a[i])
    a[k+1] = a[i];

类似于:

if (!hash_find(hash_table, a[i])) { 
    hash_insert(hash_table, a[i]);
    a[k+1] = a[i];
}

如果您的数字都在相当窄的范围内,或者您希望这些值是密集的(即,大多数值都存在),您可能希望使用位集而不是哈希表。这只是一个位数组,设置为零或一个,以指示是否已经看到一个特定的数字。

另一方面,如果您更关心复杂性的上限而不是普通情况,则可以使用基于树的平衡集合而不是哈希表。这通常会使用更多内存并且运行速度更慢,但其预期的复杂性和最差情况复杂性基本相同(O(N log N))。在最坏的情况下,典型的哈希表从常数复杂度退化为线性复杂度,这将使您的整体复杂度从O(N)变为O(N 2 )。

答案 5 :(得分:0)

你的逻辑错了,所以代码也错了。在编码之前自己做你的逻辑。 我建议采用O(NlnN)方式修改heapsort。 使用heapsort,我们从[i]加入到[n],找到最小值并用[i]替换它,对吧? 所以现在是修改,如果最小值与[i-1]相同,那么交换最小值和[n],将数组项的数量减少1。 它应该以O(NlnN)方式完成。

答案 6 :(得分:0)

您的代码仅适用于特定情况。显然,您正在检查相邻值,但重复值可能出现在数组中的任何位置。因此,这是完全错误的。