Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用内存高效的方法查找阵列中的重复项_C#_Arrays_Algorithm_Out Of Memory_Memory Efficient - Fatal编程技术网

C# 使用内存高效的方法查找阵列中的重复项

C# 使用内存高效的方法查找阵列中的重复项,c#,arrays,algorithm,out-of-memory,memory-efficient,C#,Arrays,Algorithm,Out Of Memory,Memory Efficient,A是一个整数数组 所有值都在0到A.Length-1 这意味着0不需要另一个数据结构。您可以将输入本身用作哈希集 每次看到一个值时,在对应于该索引的项中添加一个.Length。由于值可能已经增加,您应该将该值视为A[i]mod A.length 如果您找到的项目已>=A.length。。你重复了一遍。(请记住,问题表明所有项目都在间隔[0,A.Length-1]) 跟踪已发现的重复的最低索引 这导致O(N)复杂度(单次传递),并且不使用额外的数据结构,即大小O(1) 这种方法背后的关键概念是哈希

A
是一个整数数组

所有值都在
0
A.Length-1


这意味着
0不需要另一个数据结构。您可以将输入本身用作哈希集

每次看到一个值时,在对应于该索引的项中添加一个.Length。由于值可能已经增加,您应该将该值视为
A[i]mod A.length

如果您找到的项目已>=A.length。。你重复了一遍。(请记住,问题表明所有项目都在间隔
[0,A.Length-1]

跟踪已发现的重复的最低索引

这导致O(N)复杂度(单次传递),并且不使用额外的数据结构,即大小O(1)

这种方法背后的关键概念是哈希集以这种方式工作。从概念上讲,这与鸽子洞原理间接相关。

注:在访谈过程中,重要的是询问具体实施问题,讨论限制、假设等: -列表中项目的数据类型是什么? -如果值在[0..A.length-1]范围内,所有项目是否都未签名?如果需要,是否可以使用负数? -等等

在面试过程中,我不会说这是一个完美的答案,相反,我会与面试官讨论这些假设,并做出相应的调整。例如,另一个答案建议使用负数,但项的数据类型可能是无符号类型,等等


本次面试旨在引发一场技术讨论,探讨您的知识和创造力。

注意:如果存在值为零的元素,则解决方案将失败。Olivier的解决方案可以处理此类情况。

使索引为[i]的元素为负值。它只经过一次循环

for(int i=0; i<A.Length; i++)
    {
        if (A[Math.Abs(A[i])] < 0){ return Math.Abs(A[i]);}
        A[Math.Abs(A[i])] = -A[Math.Abs(A[i])];
    }

对于(int i=0;i对于希望实现该问题的人,我建议使用两种变体(在c#中,如标签中),一种使用可接受的答案,另一种使用另一个答案的近似值,使用元素的对立面。然而,最后一种解决方案的值为零存在问题,需要一些技巧

第一种解决方案
使用系统;
公共课程
{
公共静态void Main()
{
int[]a={3,4,0,5,2,3};
int N=6;
int min_指数=0;
bool-found=false;
int指数=-1;
int i=0;
而(i=N)
指数=a[i]%N;
其他的
指数=a[i];
if(a[index]>=N)//是重复的元素
{
最小指数=i;
发现=真;
}否则
{
a[指数]+=N;
}
i++;
}
Console.WriteLine(“结果=”+a[min_index]%N);
}
}
第二种解决方案
使用系统;
公共课程
{
公共静态void Main()
{
int[]a={3,4,2,5,2,3};
int N=6;
int min_指数=N-1;
bool-found=false;
int指数=-1;
int i=0;
而(i0)
{
a[索引]=-a[索引];
}否则
{
a[指数]+=-N+1;
}
}
i++;
}
如果(a[min_索引]=-N+1)
a[min_索引]=0;
Console.WriteLine(“Result=“+Math.Abs(a[min_index]));
}
}

我想改进@AryanFirouzian的解决方案,并通过使用
返回收益
来返回所有副本。此外,使用temp变量可以简化代码

public static IEnumerable<int> FindDuplicates(int[] A)
{
    for (int i = 0; i < A.Length; i++) {
        int absAi = Math.Abs(A[i]);
        if (A[absAi] < 0) {
            yield return absAi;
        } else {
            A[absAi] *= -1;
        }
    }
}
它回来了

[4] = 2
[5] = 3
我的最终解决方案消除了所有这些问题(至少我希望如此):它通过在第一次出现的值中添加
(I+1)*A.Length
来对第一个索引本身进行编码。
(I+1)
,因为
I
可以是
0
。然后可以使用反向操作
(A[x]/A.Length)对索引进行解码-1

然后,因为我们只想返回第一个重复值的结果,所以我们将该值设置为负值以将其排除在进一步处理之外。随后,可以使用
Math.Abs(a[i])%a.Length
检索原始值

public static IEnumerable<(int index, int value)> FindDuplicates(int[] A)
{
    for (int i = 0; i < A.Length; i++) {
        int x = Math.Abs(A[i]) % A.Length;
        if (A[x] >= 0) {
            if (A[x] < A.Length) { // First occurrence.
                A[x] += (i + 1) * A.Length; // Encode the first index.
            } else { // Second occurrence.
                int firstIndex = (A[x] / A.Length) - 1; // Decode the first index.
                yield return (firstIndex, x);

                // Mark the value as handeled by making it negative;
                A[x] *= -1; // A[x] is always >= A.Length, so no zero problem.
            }
        }
    }
}
我们的元素是没有标识的整数。也就是说,我们可以在任何索引处返回其中一个重复的整数,因为无法区分两个相等的整数。如果元素具有标识(它们可以是具有相同值但不同引用的引用类型,或者具有不涉及相等测试的附加字段),我们必须返回第一次出现的

yield return (firstIndex, Math.Abs(A[firstIndex]) % A.Length);

满足所有要求。

我建议使用
哈希集(但这是使用额外变量)。当
Add
返回
false
时,您得到了答案。如果没有看到示例输入和基准测试代码,是否足够有效-不确定。我还问如果我创建一个哈希表会怎么样,他拒绝了。我想这与值范围有关。您可以将输入本身用作哈希集。每次看到一个值,将a.Length添加到对应于该索引的项中。不需要其他数据结构。如果您发现一个项已经>a.Length..您有一个重复。跟踪它们看看:尝试以下操作:int[]a={3,4,2,5,2,3};int[]b=a.Select((x,i)=>new{number=x,index=i})。GroupBy(x=>x.number)。选择(x=>x.Min(y=>y.index)).ToArray();是、负或+A.length
public static IEnumerable<int> FindDuplicates(int[] A)
{
    for (int i = 0; i < A.Length; i++) {
        int absAi = Math.Abs(A[i]);
        if (A[absAi] < 0) {
            yield return absAi;
        } else {
            A[absAi] *= -1;
        }
    }
}
public static IEnumerable<(int index, int value)> FindDuplicates(int[] A)
{
    for (int i = 0; i < A.Length; i++) {
        int x = A[i] % A.Length;
        if (A[x] / A.Length == 1) {
            yield return (i, x);
        }
        A[x] += A.Length;
    }
}
var A = new int[] { 3, 4, 2, 5, 2, 3, 3 };
foreach (var item in FindDuplicates(A)) {
    Console.WriteLine($"[{item.index}] = {item.value}");
}
[4] = 2
[5] = 3
public static IEnumerable<(int index, int value)> FindDuplicates(int[] A)
{
    for (int i = 0; i < A.Length; i++) {
        int x = Math.Abs(A[i]) % A.Length;
        if (A[x] >= 0) {
            if (A[x] < A.Length) { // First occurrence.
                A[x] += (i + 1) * A.Length; // Encode the first index.
            } else { // Second occurrence.
                int firstIndex = (A[x] / A.Length) - 1; // Decode the first index.
                yield return (firstIndex, x);

                // Mark the value as handeled by making it negative;
                A[x] *= -1; // A[x] is always >= A.Length, so no zero problem.
            }
        }
    }
}
[2] = 2
[0] = 3
yield return (firstIndex, Math.Abs(A[firstIndex]) % A.Length);