我有一个面试问题,用C#编写一个程序,在一个数组中输出奇数个。
示例: [2,2,3,3,3] => [3](考虑数组已排序)
我的解决方案是:
public list<int> OddOccurance(list<int> InputList)
{
list<int> output = new list<int>();
for(int i=0; i<InputList.length; i++)
{
int Count = 0;
for(int j=1; j<(InputList.length-1); j++)
{
if(InputList[i] == InputList[j])
{
Count++;
}
}
if(Count % 2 != 0)
{
output.add(InputList[i]);
}
}
return output.distinct();
}
我认为答案是正确的,但面试官已经问过我如何以更快的方式解决问题的方法。
请有人告诉我上述解决方案的时间复杂度。
如果有办法使上述解决方案快得多,那么该解决方案的时间复杂度可能会很高。
答案 0 :(得分:1)
您的解决方案的根本问题可见于此行:
return output.Distinct();
您正在进行Distinct
这一事实意味着您可能会添加超出预期的条目。
那你怎么能优化呢?请注意,由于数组已排序,因此您可以在其旁边找到与您正在查看的数字相同的数字的唯一位置,或者在与您当前数字相等的另一个数字旁边。换句话说,你的号码是“运行”。
这个观察结果允许您从两个嵌套循环和一个O(N 2 )解决方案转到单个循环和O(N)解决方案。只需遍历数组,并检查每个“运行”的长度:当您看到一个新数字时,存储其索引。如果您遇到一个新号码,看看“run”的长度是否为奇数,并开始新的运行:
int start = 0;
int pos = 1;
while (pos < InputList.Length) {
if (InputList[pos] != InputList[start]) {
if ((pos-start) % 2 == 1) {
output.Add(InputList[start]);
}
start = pos;
}
pos++;
}
// Process the last run
if ((InputList.Length-start) % 2 == 1) {
output.Add(InputList[start]);
}
答案 1 :(得分:1)
您的解决方案是O(n^2)
- 如果您不知道原因 - 请评估总和:
这是一个描述算法运行时间的公式。你可以很容易地在线性时间内解决它 - 只需在数组中的所有值上增加i
而不是内循环。
for (int i=0; i<InputList.Length; ++i)
{
int currentValue = InputList[i];
int j=i+1;
int count = 1;
while (InputList[j] == currentValue && j<InputList.Length)
{
count++;
i++;
j++;
}
if (count % 2 == 0)
..
}
如果数组未排序 - 使用字典(散列表 - C#中的字典) - value是字典键,count是字典值。 (这将为您提供包含密钥检查O(1)
)另一种获得线性时间的方法,如果实施得当。