寻找出现m次的数字

一个数组中,仅有一个数字出现m次,其余数字均出现n次,m不等于n,找出这个出现m次的数字。

n = 2, m = 1

这是通常遇到的情形,利用 x ^ x = 0x ^ 0 = x可在O(n)时间内找出仅出现1次的数字

n = 3, m = 1

常见的情形,将这个仅出现1次的数字的二进制每一位求出来,其余出现3次的数字模3均为0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int FindNumber(int a[], int n)
{
int bits[32];
int i, j;
memset(bits, 0, 32 * sizeof(int));
for (i = 0; i < n; i++)
for (j = 0; j < 32; j++)
bits[j] += ((a[i] >> j) & 1);
int result = 0;
for (j = 0; j < 32; j++)
if (bits[j] % 3 != 0)
result += (1 << j);
return result;
}

n任意,m % n != 0

进一步,若m不等于1,则模n后的结果是该数字在该位上%n。因此要将累加后的结果除以一个倍数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int f(const vector<int> &v, int n, int m)
{
if (n <= 0 || m <= 0)
return numeric_limits<int>::min();
int result = 0;
if (!(n & 1) && m == 1)
{
for (const auto &x : v)
result ^= x;
return result;
}

int add = 0;
int remain = m % n;
if (!remain)
return numeric_limits<int>::min();

for (int i = 0; i < 32; ++i)
{
add = 0;
for (const auto & x : v)
add += (x >> i) & 1;
if (m < n)
add = (add % n) == m ? 1 : 0;
else
add = (add % n) == remain ? 1 : 0;
result |= (add << i);
}
return result;
}
示例
示例

对于m % n = 0的情况,需要进一步分析是否存在类似的方法。

------ 本文结束 ------

版权声明

Memory is licensed under a Creative Commons BY-NC-SA 4.0 International License.
博客采用知识共享署署名(BY)-非商业性(NC)-相同方式共享(SA)
本文首发于Memory,转载请保留出处。