Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.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# 如何实现该函数的O(n)最坏情况时间复杂度?_C#_Arrays_Algorithm_Time Complexity_Big O - Fatal编程技术网

C# 如何实现该函数的O(n)最坏情况时间复杂度?

C# 如何实现该函数的O(n)最坏情况时间复杂度?,c#,arrays,algorithm,time-complexity,big-o,C#,Arrays,Algorithm,Time Complexity,Big O,我对某项任务有意见。这不是家庭作业什么的,现在是个人的事了。我想知道是否有解决这个问题的办法 关键是要实现函数的预期O(n)最坏情况时间复杂度,该函数采用两个字符串数组作为输入(让我们调用第一个a,第二个数组B),并应返回一个整数数组,其中每个元素表示数组a中对应元素的索引 因此,函数应该是这样的: private static int[] GetExistingStrings(string[] A, string[] B) { ... } 数组A包含所有可能的名称 数组B包含应排除的名称(

我对某项任务有意见。这不是家庭作业什么的,现在是个人的事了。我想知道是否有解决这个问题的办法

关键是要实现函数的预期O(n)最坏情况时间复杂度,该函数采用两个字符串数组作为输入(让我们调用第一个
a
,第二个数组
B
),并应返回一个整数数组,其中每个元素表示数组
a
中对应元素的索引

因此,函数应该是这样的:

private static int[] GetExistingStrings(string[] A, string[] B) { ... }
  • 数组
    A
    包含所有可能的名称
  • 数组
    B
    包含应排除的名称(即,如果
    B
    数组中存储的某些名称也在
    A
    数组中,则其索引不应包含在输出int[]数组;该数组也可能包含一些随机字符串,这些字符串不一定存在于
    A
    数组中,甚至可能为空
例如,如果我们有以下阵列:

string[] A = { "one", "two", "three", "four" }; // 0, 1, 2, 3
string[] B = { "two", "three" }; // Indices of "two" and "three" not taken into account
该函数应返回:

int[] result = { 0, 3 }; // Indices of "one" and "four"
起初,我尝试用简单明了的方法(使用嵌套for循环)来实现:

private static int[]getExistingString(字符串[]A,字符串[]B)
{
LinkedList aIndices=新建LinkedList();
对于(int n=0;n
我使用LinkedList是因为我们不可能知道输出的数组大小应该是多少,也因为向这个列表中添加新节点是一个常量O(1)操作。当然,这里的问题是,这个函数(我假设)的时间复杂度是O(n*M)。因此,我们需要找到另一种方法

我的第二个方法是:

private static int[] GetExistingStrings(string[] A, string[] B)
{
    int n = A.Length;
    int m = B.Length;

    if (m == 0)
    {
        return GetDefaultOutputArray(n);
    }

    HashSet<string> bSet = new HashSet<string>(B);
    LinkedList<int> aIndices = new LinkedList<int>();

    for (int i = 0; i < n; i++)
    {
        if (!bSet.Contains(A[i]))
        {
            aIndices.AddLast(i);
        }
    }

    if (aIndices.Count > 0)
    {
        int[] result = new int[aIndices.Count];
        aIndices.CopyTo(result, 0);
        return result;
    }

    return GetDefaultOutputArray(n);
}

// Just an utility function that returns a default array
// with length "arrayLength", where first element is 0, next one is 1 and so on...
private static int[] GetDefaultOutputArray(int arrayLength)
{
    int[] array = new int[arrayLength];
    for (int i = 0; i < arrayLength; i++)
    {
        array[i] = i;
    }
    return array;
}
private static int[]getExistingString(字符串[]A,字符串[]B)
{
int n=A.长度;
int m=B.长度;
如果(m==0)
{
返回GetDefaultOutputArray(n);
}
HashSet bSet=新的HashSet(B);
LinkedList aIndices=新建LinkedList();
对于(int i=0;i0)
{
int[]结果=新的int[aIndices.Count];
aIndices.CopyTo(结果为0);
返回结果;
}
返回GetDefaultOutputArray(n);
}
//只是一个返回默认数组的实用函数
//长度为“arrayLength”,其中第一个元素为0,下一个元素为1,依此类推。。。
私有静态int[]GetDefaultOutputArray(int arrayLength)
{
int[]数组=新的int[arrayLength];
对于(int i=0;i
这里的想法是将
B
数组的所有元素添加到HashSet中,然后使用它的方法
Contains()
检查for循环中的相等性。但我无法计算此函数的时间复杂度…我确信for循环中的代码将执行
n次
次。但最让我头疼的是哈希集初始化-这里应该考虑它吗?它如何影响时间复杂度?此函数是否O(n) ?或O(n+m)因为哈希集初始化


有没有办法解决这个问题并实现O(n)

如果
A
中有
n
元素,
B
中有
m
元素,并且字符串的长度为
k
,哈希映射方法的预期时间是
O(k*(m+n))
。不幸的是,最糟糕的时间是
O(km(m+n))
如果散列算法不起作用(可能性很低)。我以前犯过这个错误,多亏@PaulHankin的纠正

为了得到
O(k*(m+n))
最坏的时候,我们必须采取一种非常不同的方法。你要做的是从B中构建a。现在你要遍历
a
的每个元素,并在trie中查找它。与散列不同,trie保证了最坏情况下的性能(更好的是,允许前缀查找,即使我们不使用它)这种方法不仅给出了预期的平均时间
O(k*(m+n))
,而且给出了相同的最坏时间


您不能做得比这更好,因为仅处理列表需要处理
O(k*(m+n))
数据。

以下是如何使用LINQ重写第二种方法,同时选择不区分大小写的字符串比较:

public static int[] GetExistingStrings(string[] first, string[] second)
{
    var secondSet = new HashSet<string>(second, StringComparer.OrdinalIgnoreCase);
    return first
        .Select((e, i) => (Element : e, Index : i))
        .Where(p => !secondSet.Contains(p.Element))
        .Select(p => p.Index)
        .ToArray();
}
public static int[]getExistingString(字符串[]第一,字符串[]第二)
{
var secondSet=newhashset(第二个,StringComparer.OrdinalIgnoreCase);
先返回
.选择((e,i)=>(元素:e,索引:i))
.Where(p=>!secondSet.Contains(p.Element))
.选择(p=>p.Index)
.ToArray();
}

时间和空间复杂度是相同的(O(n))。这只是做同样事情的一种更为奇特的方式。

使用具有预设容量的列表,而不是链表。列表的构造函数允许您指定容量。类似于.Count的值应该是一个很好的上限。在实际遇到问题之前,不要使用链表。它们的性能与旧的好列表相比非常糟糕列表。最糟糕的情况是,在末尾添加一些内容,需要遍历整个现有列表(以找到需要添加内容的元素)。“有没有办法解决此任务并实现O(n)?”。没有。您可以得到的最好结果可能是O(m*log(n)).在什么情况下了解复杂性是重要的?您是否运行了数百万次/数十亿次这样的代码
public static int[] GetExistingStrings(string[] first, string[] second)
{
    var secondSet = new HashSet<string>(second, StringComparer.OrdinalIgnoreCase);
    return first
        .Select((e, i) => (Element : e, Index : i))
        .Where(p => !secondSet.Contains(p.Element))
        .Select(p => p.Index)
        .ToArray();
}