【发布时间】:2011-06-13 22:34:29
【问题描述】:
给定一个数字数组,除了一个数字之外的所有其他数字,都会出现 两次。应该是什么算法来找到只出现一次的数字 数组?
例子
a[1..n] = [1,2,3,4,3,1,2]
应该返回 4
【问题讨论】:
标签: algorithm
给定一个数字数组,除了一个数字之外的所有其他数字,都会出现 两次。应该是什么算法来找到只出现一次的数字 数组?
例子
a[1..n] = [1,2,3,4,3,1,2]
应该返回 4
【问题讨论】:
标签: algorithm
int i = 0
XOR 每一项都带有i
i 中将有预期的数字
【讨论】:
设数组中只出现一次的数字为x
x <- a[1]
for i <- 2 to n
x <- x ^ a[i]
return x
由于a ^ a = 0和a ^ 0 = a
成对出现的数字相互抵消,结果存储在x
C++ 中的工作代码
#include <iostream>
template<typename T, size_t N>
size_t size(T(&a)[N])
{
return N;
}
int main()
{
int a [] = {1,2,3,4,3,1,2};
int x = a[0];
for (size_t i = 1; i< size(a) ; ++i)
{
x = x ^ a[i];
}
std::cout << x;
}
【讨论】:
sizeof(a)/sizeof(a[0]) 还不够?
我只知道蛮力算法,它是遍历整个数组并检查
代码将类似于(在 C# 中):
k=0;
for(int i=0 ; i < array.Length ; i++)
{
k ^= array[i];
}
return k;
【讨论】:
您可以对数组进行排序,然后找到第一个没有配对的元素。这将需要几个循环进行排序和一个循环来查找单个元素。
但更简单的方法是将双键设置为零或当前格式不可能的值。也取决于编程语言,因为与 c# 不同,您不能在 c++ 中更改键类型。
【讨论】:
zerkms 在 C++ 中的回答
int a[] = { 1,2,3,4,3,1,2 };
int i = std::accumulate(a, a + 7, 0, std::bit_xor<int>());
【讨论】:
如果您有无法合理异或的数量(例如,大整数或表示为字符串的数字),另一种方法也是 O(n) 时间,(但 O(n) 空间而不是 O(1)空间)将简单地使用哈希表。算法如下:
Create a hash table of the same size as the list
For every item in the list:
If item is a key in hash table
then remove item from hash table
else add item to hash table with nominal value
At the end, there should be exactly one item in the hash table
我愿意,C 或 C++ 代码,但它们都没有内置哈希表。(不要问我为什么 C++ 在 STL 中没有哈希表,但确实有一个基于红黑树,因为我不知道他们在想什么。)而且,不幸的是,我没有方便的 C# 编译器来测试语法错误,所以我给你 Java 代码。不过,它非常相似。
import java.util.Hashtable;
import java.util.List;
class FindUnique {
public static <T> T findUnique(List<T> list) {
Hashtable<T,Character> ht = new Hashtable<T,Character>(list.size());
for (T item : list) {
if (ht.containsKey(item)) {
ht.remove(item);
} else {
ht.put(item,'x');
}
}
return ht.keys().nextElement();
}
}
【讨论】:
std::unordered_set 和 std::unordered_map。当前的编译器已经将这些作为 TR1 库扩展。