C#:O(n²)解,用于找到大小为n和数字k的数组的n / k个元素

时间:2018-09-03 21:15:57

标签: c# arrays

Link where I got the problem from

我正在尝试一种O(n²)解决方案,以查找在给定数组中哪些元素出现的次数比n / k次( k次)(此情况下,n = 8-两次以上) 。我相信我有解决方案,但我似乎无法弄清楚为什么输出(如下所示)不是[2,3]。我知道它出现在索引i = 3的元素2上,但我认为if (count > (arr.Length / k))条件可以解决此问题。

int[] arr = { 3, 1, 2, 2, 1, 2, 3, 3 };
int k = 4, count = 1;

for(int i = 0; i < arr.Length; i++)
{
    for (int j = i + 1; j < arr.Length; j++)
    {
        if (arr[i] == arr[j])
        {
            count++;
            if (count > (arr.Length / k))
            {
                Console.WriteLine(arr[i] + " " + i);
                count = 1;
            }
        }
    }
}

输出:

3 0

2 2

2 3

2 个答案:

答案 0 :(得分:1)

问题在于,只有在存在匹配项且count大于count时,您才重置arr.Length/k。您需要在内部for循环的结尾处重置它,或者最好在内部for循环之前对其进行定义,因为在该循环之外不需要它。另外,我猜想您会在count满足条件后立即退出该循环,否则您将继续写出相同的内容。

int[] arr = { 3, 1, 2, 2, 1, 2, 3, 3 };
int k = 4;

for(int i = 0; i < arr.Length; i++)
{
    int count = 1;
    for (int j = i + 1; j < arr.Length; j++)
    {
        if (arr[i] == arr[j])
        {
            count++;
            if (count > (arr.Length / k))
            {
                Console.WriteLine(arr[i] + " " + i );
                break;
            }
        }
    }
}

但是,这仍然会在其他位置产生重复值的结果。例如,数组k等于4的{3,1,2,2,1,2,3,3,3,3,3,3}产生3,0; 3,6; 3,7;和3,8。假设您只想要3.0,那么一个更好的解决方案是。

int[] arr = { 3, 1, 2, 2, 1, 2, 3, 3 };
int k = 4;    

var results = arr.Select((x,i) => new {Value = x, Index = i})
    .GroupBy(x => x.Value)
    .Where(grp => grp.Count() > arr.Length / k)
    .Select(grp => grp.First());

foreach(var r in results)
{
    Console.WriteLine($"{r.Value} {r.Index}");
}

或者,如果您更喜欢使用for循环而不是Linq,那么您只需要一个HashSet<int>来跟踪已经看到的值即可。

int[] arr = { 3, 1, 2, 2, 1, 2, 3, 3 };
int k = 4;
HashSet<int> seen  = new HashSet<int>();

for(int i = 0; i < arr.Length; i++)
{
    if(!seen.Add(arr[i]))
    {
        continue;
    }

    int count = 1;
    for (int j = i + 1; j < arr.Length; j++)
    {
        if (arr[i] == arr[j])
        {
            count++;
            if (count > (arr.Length / k))
            {
                Console.WriteLine(arr[i] + " " + i );
                break;
            }
        }
    }
}

请注意,当值已经在哈希集中时,Add返回false。

答案 1 :(得分:0)

这不是最优化的方法吗?因为您不想检查最后的arr.Length/k个元素,因为如果所有元素都相同,那么它们在数量上只会是are.Length/k而不是> are.Length/k

int[] arr = { 3, 1, 2, 2, 1, 2, 3, 3 };
int k = 4;
int target = arr.Length/k;
for(int i = 0; i < arr.Length - target; i++)
{
    int count = 1;
    for (int j = i + 1; j < arr.Length; j++)
   {
        if (arr[i] == arr[j])
       {
           count++;
           if (count > (target))
           {
               Console.WriteLine(arr[i] + " " + i );
               break;
           }
       }
   }
}

如果您可以使用一种算法来排序O(n log n)或更小,那么类似的事情可能会有用:

int[] arr = { 3, 1, 2, 2, 1, 2, 3, 3 };
int[] sorted = Sort(arr); //sort method
int k = 4;
int target = arr.Length/k;
int count = 0;
for(int i = 0; i < arr.Length - target; i++)
{
     count++;
     if(arr[i] != arr[i+1])
     { 
        if(count > target)
           Console.WriteLine($"{arr[i]} {count}");
        count = 0;
     }
}