最近在一次采访中,我被要求编写一个python代码来从列表中删除所有重复的条目。
例如:
Input List = {1,2,4,5,2,3,1}
Expected Output List = {4,5,3}
在上面的示例中,1和2出现多次,应将其删除。秩序的保存是很重要的。这就是问题所在。
他又一次不希望我使用内置函数,如set()、unique()等。我猜他是在测试我的算法和ds技巧。他在一开始就讲清楚了。
我想了两种方法。1.)排序(nlog(n)的复杂性)2.)哈希表(排序更快)
哈希表方法:
arr = [1,2,4,5,2,3,1]
//function : to create a hash table with key = arr[i] & value = occurence count
def dataCountTable(arr):
countTable = {}
i = 0
while i
if arr[i] in countTable :
countTable[arr[i]] += 1
else :
countTable[arr[i]] = 1
i+=1
return countTable
//function : to remove duplicates using the arr & hash table
def rmvAllDuplicate(arr, countTable):
outList = list()
i = 0
while i
if countTable[arr[i]] == 1 :
outList.append(arr[i]);
i+=1
return outList
print rmvAllDuplicate(arr, dataCountTable(arr))
面试官似乎对这个答案没有印象。它让我一直在寻找更好的围裙。我找不到。
如果有人能帮助我改进我的解决方案,或者建议一个新的更好的解决方案,那就太好了!
谢谢!
如果你不介意点菜,就用一套吧
保留编辑顺序是问题的一部分。他不希望我使用像unique()之类的内置函数
stackoverflow.com/questions/7961363/…
另请参阅删除重复项的最快算法。这与您的问题不同,但它是一个很好的基础,可以证明基于哈希的方法在实践中是最快的。
我将使用collection.Counter来实现这一点(或自己实现一个):
from collections import Counter
input_list = [1,2,4,5,2,3,1]
# expected_output_list = {4,5,3}
# make Counter object for list elements
# and pick up to list only those values for which count is 1
singles = {x for x, count in Counter(input_list).items() if count == 1}
# filter your list to get only elements that were not duplicates
result = [x for x in input_list if x in singles]
或者正如@forstru指出的那样,您可以:
result = [x for x, count in Counter(input_list).items() if count == 1]
但在这种情况下,您不能保证保留您的列表的顺序(h/t@dsm)
这具有线性时间复杂性。
最后的清单理解是多余的:singles = [x for x, count in Counter(input_list).items() if count == 1]。
这不是多余的:订单保存很重要。
事实上,对于列表,您可以缩短它;我已经从我脑海中的字典中删除了重复的值;)
这是一个更加简洁/易读/更快一点一点的常量版本,是OP在其编辑中添加的"哈希表方法"…
虽然哈希表的实现可以变得更简洁、易读、更惯用,但速度会稍微提高一点,但我怀疑这并不是你的面试官失望的地方。
更可能的是,他推动你寻求一个更好的解决方案,希望你能提出一个论点,为什么你的解决方案实际上是最佳的,但相反,你搜索了一段时间,放弃了。
所以,这里有很多事情要证明:
这个问题的任何解决方案都必须是O(N)时间。
您的解决方案是(摊销、平均和几乎总是)O(n)时间。
解决方案时间复杂性中的乘数是合理的。
任何解决这个问题的O(n)时间必须是O(m)空间(其中m是不同值的数目)。
您的解决方案是O(M)空间。
解决方案空间复杂性的乘数是合理的。
即使是那些简单的,你也不会在面试中拿出真正严格的证据。其中一些人,你甚至不能提出令人信服的理由,但提出可能的例外,承认你在哪里挥手可能就足够了。例如:
python的dict和set的最坏情况时间为o(n);这只是o(1)的摊余平均情况。您的数据是否有任何可能比O(1)更糟的地方?可能不是,但是……如果这是有人想要做的服务器的一部分,并且他们可以发送他们想要的任何输入数据,那该怎么办?
他给你的所有值都是小整数。这是真的吗?在这种情况下,不要用口述来计算,只要用list(range(0, P)),其中P是最大数。然后是O(P)空间,这听起来比O(M)更糟,只是乘数要小得多——列表占空间的1/3(只是值,而不是哈希、键和值),所以如果P << M/3是一个胜利。这也可能是速度上的胜利,因为不需要保持散列值。你可以更好地使用array.array。
python散列表对于存储集合和小计数的dict来说是多余的。自定义哈希表是否可以显著地减少数据量,或者不足以使其值?
顺便说一下,就我个人而言,我认为"除了小整数什么都没有"的问题非常重要,我很高兴听到你马上问我这个问题。但我已经和在谷歌和微软等地进行采访的人谈过了,他们都告诉我他们会回答"不,你不能对数据做任何假设",然后继续前进。不过,我不在乎你在谷歌或微软找到一份工作,也不在乎你写好的代码,不管谁雇佣你,所以我还是建议你问这样的问题。
这是一个很好的解释,谢谢!-我会把这个作为答案。
我猜如果不允许使用内置函数,也不允许使用stdlib类。否则,一定要用瓦索夫斯基先生的回答。
但你能自己做同样的事吗?
当然,一个Counter只是一个花哨的dict而已。您可以实现自己的Counter,或者直接执行相同的工作:
input_list = [1,2,4,5,2,3,1]
counts = {}
for value in input_list:
counts.setdefault(value, 0)
counts[value] += 1
现在和他的其他代码一样:
singles = {x for x, count in counts.items() if count == 1}
result = [x for x in input_list if x in singles]
这实际上与您在"哈希表方法"中所做的相同。但它更简洁,更易读,更惯用,更快,一个小但非零常数,所以它可能仍然给面试官留下了更深刻的印象。(当然,所有这些对瓦索夫斯基先生的版本来说都更为真实。)
您可以在一行中理解列表:
in_list = [1,2,4,5,2,3,1]
out_list = [num for num in in_list if in_list.count(num) == 1]
# result: [4,5,3]
我想这是我们所期望的……我对单子的理解不好。
这里的运行时间是多少?如果清点是幼稚的,那就是O(N^2),但如果我错了,请纠正我。
清单理解当然值得学习。
@不可否认的是,这是O(N&178;)。
是-这是O(n^2),因为if in_list.count(num)==1。
尝试:简单
l=[1,2,4,5,2,3,1]
[x for x in l if l.count(x)==1 ]
它将删除所有唯一的项目
为什么要投票????
您的回答(编辑前/编辑后)没有给出预期的输出({4,5,3})
你的答案仍然有错误…结果应该只有[4,5,3],而你的software给[4,5,2,3,1]。
OP希望完全删除任何重复的号码,而不仅仅是删除重复的号码。
希望一切都独一无二,而不是重复,
明白了,我的错没能读懂。
@现在检查代码
您的代码现在非常类似于Figs。解释与代码相反。
类似的是,我使用了内置的count函数,而不是任何额外的变量。
@Hackaholic,都使用了列表理解,list.count方法。只有用于变量的名称不同。
python中的set是一个没有重复项的集合。您可以获取一个列表并删除重复的项目,方法是将其转换为set,然后返回到一个列表:
l = [1,2,3,2,4,3]
l = list(set(l))
print l
output: [1,2,3,4]
是这个答案还是另一个问题?你能解释一下吗?
遍历列表,并为您在列表中看到的特定元素设置一个标记。如果您再次遇到同一个元素,标记将已经设置,您不想再将该元素添加到列表中。这将导致一个线性时间算法。这就是面试官对你的解决方案不满意的原因。哈希实际上也有相同的作用,但您正在为维护哈希表创建一个巨大的重载。
def f(seq):
seen = {}
result = []
for item in seq:
if item in seen: continue
seen[item] = 1
result.append(item)
return result
这只是统一了列表。这不是问题所在。您将给出输出[1, 2, 4, 5, 3],而不是[4, 5, 3]。(同样,用听写来模拟一个场景,而不是仅仅使用一个场景,可能不会给面试官留下太多印象。)
啊,斯纳布迪特把问题读得很好。但你也可以用同样的想法来得到副本。我还以为看到的是一套LOL
是的,在python中,{}不是一个空的集合有点烦人……但是如果它是一个集合,seen[item] = 1将是错误的;它只是seen.add(item)。