计算数组中的不同值 - C ++

时间:2011-10-30 22:14:03

标签: c++ arrays

我正在尝试自学(重新学习)C ++并通过在线书籍和测试来解决问题以获得一些练习。我遇到了这个让我有点困惑的问题。我最好怎么做呢?

我必须写一个函数

class Solution { public int distinct (int [] A); }

返回数组A中不同值的数量。 我可以假设数组范围是0到100,000。并且元素都是+或 - 1,000,000的整数。 有任何想法吗?我正在考虑循环并计算每个值,但这可能效率非常低吗?提前谢谢。

5 个答案:

答案 0 :(得分:6)

修改更新:包含空间优化算法以及娱乐

您可以使用std :: set来包含唯一值。只需将数组元素复制到一个集合中(无论如何你喜欢),然后计算集合中唯一元素的数量。

这是一段相当简洁的代码,它甚至不需要你指定数组的大小(不过,通常在c ++中你仍然使用std::vector):

http://ideone.com/rpWGS 上查看(包含测试数据和输出)

#include <set>

class Solution 
{ 
   public: 

     // using std::set (max O(n) additional storage)
     template<size_t N>
         static size_t distinct (int (&a)[N])
     {
         return std::set<int>(a, a+N).size();
     }

     // using std::unique (inplace mutation; no additional storage)
     template<size_t N> 
         static size_t distinct_optim(int (&a)[N])
     {
         std::sort(a, a+N);
         int* newend = std::unique(a, a+N);
         return newend - a; 
     }

};

答案 1 :(得分:6)

您的解决方案相当有效(实际上,就时间复杂度而言,尽可能高效),但在空间中 - 要计算值,您需要一个大小与可能值范围相对应的数组,因此,计算100,000个项目数组中的实例,需要一个约2,000,000个项目的辅助数组(范围从-1,000,000到1,000,000)。

您有两种方法可以避免/减少这种情况。一种是为每个可能的输入存储一位,并在看到该输入时设置该位。这具有相同的基本复杂度,但是将计数空间减少到必要的最小值(即,您并不关心任何输入发生了多少次,只是它是否发生)。在C ++中,显而易见的方法是std::vector<bool>。虽然经常受到诽谤,但在这种情况下,vector<bool>完全符合您的要求。

另一种可能性是使用从输入数到计数/位的稀疏映射。特别是当您的范围远大于输入数量时,这可以节省相当多的空间(所占用的空间将与输入数量成比例,而不是范围)。在C ++中,显而易见的方法是std::set<int>。为了保持相同的预期复杂度(O(N)而不是O(N log N),您需要使用unordered_set代替。

另一种可能性是对输入进行排序,然后消除重复。这通常使辅助存储器保持最小,但通常需要稍长的时间来执行(O(N log N)而不是O(N))。为此,您可能会使用std::vectorstd::sortstd::unique

答案 2 :(得分:2)

对数组A进行排序 然后遍历排序的数组并计算两个连续数字之间的差异非零的次数。 确保您处理数组的边缘以及数组大小为1的情况。

答案 3 :(得分:1)

我可以想到两个选择:

1)使用快速排序或合并排序对矢量进行排序,然后迭代排序后的矢量,每次遇到与当前值不同的值时计数。

2)设置大小为1,000,000的std::vector<bool>,并在迭代数组时输入true值。之后,您计算true值的数量。我说vector<bool>因为它针对高效存储进行了优化,即它可能在一个字节中存储8个bool。

答案 4 :(得分:1)

为了获得数组中不同值的数量,我可以看到两种可能性。

首先是对它们进行排序,然后计算转换次数(加1)。例如,以下列表:

1 1 1 1 2 2 3 4 4 5
       ^   ^ ^   ^

有四个转换,因此有五个distint值。

另一种可能性是建立一个“布尔”数组,表明之前是否有过一个数字,伪代码如(在你的情况下):

def countDistinct (array):
    def notSeenYet[-1,000,000..1,000,000] as all true
    count = 0
    for each value in array:
        if notSeenYet[value]:
            notSeenYet[value] = false
            count = count + 1
    return count

第一种要求排序最多为O(n log n)时间复杂度。对于100,000个元素,这不太可能是一个严重的问题,但您可能不希望以任何方式修改数组(这需要复制,O(n)空间复杂度)。

第二个是O(n)时间复杂度和持续存储的情况。两百万个布尔值可能值得关注,具体取决于您的环境,但是,如果它可用,那就更好了,假设时间是您的主要关注点(通常是)。