之前和之后的集合发生了什么变化

时间:2013-08-11 22:14:31

标签: algorithm

这是一个面试问题:你有两个阵列:之前:{3,3,5,8,1}和之后:{5,3,2,4}。确定从'之前'数组中删除/添加了哪些数字以获得'之后'。

我可以考虑为每个列表使用两个哈希映射作为并比较每个列表以告知是否已添加或删除每个元素。

有人可以考虑采用更好的方法,还是为此提供替代解决方案(更好的时间/空间补充)?

3 个答案:

答案 0 :(得分:0)

您可以将每个列表存储在行李中,然后查找行李中每种物品类型的发生变化。

这是一些Python:

>>> # Original data
... l1, l2 = [3,3,5,8,1], [5,3,2,4]
>>> # Pythons Counter class in also known as a bag
... from collections import Counter
>>> c1, c2 = Counter(l1), Counter(l2)
>>> # Quick calculation
... diffs = {item:(c2[item] - c1[item]) for item in set(c1) | set(c2)}
>>> diffs
{1: -1, 2: 1, 3: -1, 4: 1, 5: 0, 8: -1}
>>> # Or if you want it wordy
... for item in sorted(set(c1) | set(c2)):
...     print('Item %i changed its occurences by %2i'
...           % (item, c2[item] - c1[item]))
... 
Item 1 changed its occurences by -1
Item 2 changed its occurences by  1
Item 3 changed its occurences by -1
Item 4 changed its occurences by  1
Item 5 changed its occurences by  0
Item 8 changed its occurences by -1
>>>  

答案 1 :(得分:0)

上述线程之一中讨论的解决方案是O(n + m)n,​​m是2个数组的大小,因为在最坏的情况下你需要通过两个数组的整个长度进行迭代。可能的改进是对第一个数组中的第二个数组中的每个元素执行二进制搜索,然后将其从第一个数组中删除(如果找到它)。如果没有将它添加到数组中。在所有迭代之后,添加剩余的元素第一个数组到最终数组列表。时间复杂度为O(mlogn)

function binaryIndexOf(searchElement, searchArray) {
'use strict';
var minIndex = 0;
var maxIndex = searchArray.length - 1;
var currentIndex;
var currentElement;

while (minIndex <= maxIndex) {
    currentIndex = (minIndex + maxIndex) / 2 | 0;
    currentElement = searchArray[currentIndex];

    if (currentElement < searchElement) {
        minIndex = currentIndex + 1;
    }
    else if (currentElement > searchElement) {
        maxIndex = currentIndex - 1;
    }
    else {
        return currentIndex;
    }
}

return -1;
}
var before = [3, 3, 5, 8, 1];
var after = [5, 3, 2, 4];
var intsort = function (a, b) {
return a - b
};
var i;
var resultArray = [];
var elementIndex;
before.sort(intsort);
after.sort(intsort); 
for (i = 0; i < after.length; i++) {
 elementIndex = binaryIndexOf(after[i], before);
 if (elementIndex != -1)
        before.splice(elementIndex, 1);
 else
        resultArray.push(after[i]);
 }
j = 0;
while (j < before.length) { 
  resultArray.push(before[j++]); 
}
console.log("result=" + resultArray);

答案 2 :(得分:0)

我认为你建议的答案(使用两个哈希图)是最好的结果,即O(n + m),因为你总是需要至少访问一次每个数组的每个元素。

以下是我用C#实现的概念:

var b = new [] {3, 3, 5, 8, 1}.ToLookup(k => k);
var a = new [] {5, 3, 2, 4}.ToLookup(k => k);

b.Select(k => k.Key)
 .Concat(a.Select(k => k.Key))
 .Distinct()
 .ToDictionary(k => k, v => (a.Contains(v) ? a[v].Count() : 0) - (b.Contains(v) ? b[v].Count() : 0))
 .Dump(); // linqpad

我使用了很多linq来保持简洁;使用等效的循环和HashSets重写可能会更有效。