C#改进算法

C#改进算法,c#,generics,C#,Generics,在访谈(C#3.0)中,我被要求提供从列表中删除项目列表的逻辑 我回答 int[] items={1,2,3,4}; List<int> newList = new List<int>() { 1, 2, 3, 4, 5, 56, 788, 9 }; newList.RemoveAll((int i) => { return items.Contains(i); }); int[]项={1,2,3,4}; List newList=newList(){1,2,3

在访谈(C#3.0)中,我被要求提供从列表中删除项目列表的逻辑

我回答

int[] items={1,2,3,4}; 
List<int> newList = new List<int>() { 1, 2, 3, 4, 5, 56, 788, 9 };
newList.RemoveAll((int i) => { return items.Contains(i); });
int[]项={1,2,3,4};
List newList=newList(){1,2,3,4,5,56,788,9};
RemoveAll((inti)=>{returnitems.Contains(i);});
1) 面试官回答说,如果项目增加,我使用的算法将逐渐需要时间,并要求我给出更好更快的算法。高效的算法是什么

2) 如何使用LINQ实现同样的效果

3) 他让我提供一个双向关闭的例子?(将军,我知道已经结束了, 什么是双向关闭?我回答说,没有这样的术语存在,但他没有
满足)。

编辑更好的解决方案:使用非对称的,不像
相交

1和2:您可以使用扩展方法来执行此操作。但是,如果第二个数组包含在第一个数组中找不到的元素,则这些元素将出现在结果列表中:
Intersect
对称工作


至于“双向闭包”,我从来没有听说过这个术语,我相当怀疑它是否是一个已确立的技术术语。

如果不使用除之外的
,并且如果您希望您的解决方案能够扩展到大型列表,那么最好的办法是对第二个列表进行排序,或者用它制作一个哈希表,这样对于第一个列表的每个元素,你可以很容易地在第二页中识别它。(这就是除了
之外的
的工作原理,或多或少。)

我不相信你发布的代码能工作。标准数组没有contains方法*

忽略这个问题,他在您的响应中看到的问题可能是,您的示例中的items.Contains方法对列表中包含要删除的项的每个项都执行。因此,将在该列表中搜索完整项目列表中的每个项目

正如其他人所提到的,使用Except方法会更有效

编辑:没看到你说的是C#3.0。是我的错。items1和items之间仍然存在语法错误。

您的答案是O(N^2),因为您必须在小列表中搜索大列表中的每个元素。使用哈希表或带有二进制搜索的排序列表(在整数/字符串的情况下)以及其他减少查找开销的方法,您可能会有一些运气,这至少会让您得到O(N log N)

值得注意的是,如果小列表的大小与大列表的大小不相似,那么您的解决方案是O(N*M);您可能希望首先优化通常较大的列表。如果您可以对第一个列表进行排序,这是一个不错的选择;如果不允许修改,请不要忘记对第二个列表进行排序/散列。

使用Except的示例

var exclusions = new List<int>() { 1, 2, 3, 4 };
var newList = new List<int>() { 1, 2, 3, 4, 5, 56, 788, 9 };
IEnumerable<int>result = newList.Except(exclusions);
var exclusions=newlist(){1,2,3,4};
var newList=newList(){1,2,3,4,5,56788,9};
IEnumerableresult=newList.Except(除外);
int[]items1={1,2,3,4};
List newList=newList(){1,2,3,4,5,56,788,9};
RemoveAll((inti)=>{returnitems.Contains(i);});
1) 面试官回答说 我采用的算法将 如果项目增加,则逐渐花时间 并要求我给予更好的 快一点的,效率是多少 算法

您的
items1
的长度为m,
newlist
的长度为n。由于您正在对
newlist
中的每个项目执行
items1
线性查找,因此您的解决方案是O(n*m)。在我看来,您的实现是完全可以接受的,在需要之前,我们可能不应该担心优化

然而,很明显,这对面试来说还不够好。好吧,对面试官来说什么“足够好”?谁知道呢。现在,如果你不介意在面试中冒一些风险,你可以向面试官挑战,让他提供更多关于这个问题的细节。告诉他许多因素和假设会影响我们代码的速度,尤其是数据结构的选择:

  • 假设您需要对
    newList
    进行索引访问,那么将
    items1
    转换为哈希集(具有O(1)查找)可以将算法改进为重建数组所需的O(n)时间

  • 假设
    newList
    是一个元素的“包”,这意味着我们不关心集合中元素的顺序,那么用哈希集表示
    newList
    允许我们在O(m)时间内删除m个项目

  • 假设我们需要保留集合中元素的插入顺序,您可以将
    newList
    表示为LinkedList{T},同时使用字典{T,LinkedListNode}作为查找表。将项目添加到集合时,将其添加到LinkedList,然后将新创建的节点添加到字典。LinkedList保持插入顺序,字典允许我们在O(m)时间内删除m个项目。但是,我们牺牲了对集合的索引访问

  • 假设
    newList
    将项目保持在排序顺序(所提供的示例代码似乎不是这样,但只是让我幽默一下),大多数类型的平衡二叉树将删除O(m log n)中的m个项目,它们还支持O(n)排序顺序遍历。或者,如果你心情正常,跳过列表也会起到同样的作用,只是更愚蠢而已

3) 他让我举个例子 双向关闭?(我是将军 意识到结束意味着什么 “双向关闭?”我回答说我有 我听过这个词,但他没有 满足)


我也从来没有听说过它,谷歌似乎也没有找到任何相关的文章(除了这条线索,前5页的结果都与编程甚至计算机无关)。面试官是个白痴。

这听起来像经典的“我比你聪明”面试。跑,不要走,离开那个地方。哈哈——当时的想法非常一致,尤其是关于“双向关闭”?一些热心的程序员试图证明他的m
int[] items1={1,2,3,4}; 
List<int> newList = new List<int>() { 1, 2, 3, 4, 5, 56, 788, 9 };
newList.RemoveAll((int i) => { return items.Contains(i); });