来源:http://www.geeksforgeeks.org/find-the-element-that-appears-once/
问题:在一个数组中,其中有一个元素只出现一次,其余元素都出现三次,如何在O(n)的时间复杂度和O(1)的复杂度内找到那个元素。
首先我的想法是,一个数如果出现了三次,则这个数的二进制对应的位上1的个数肯定为3.这样我们可以枚举每一位,计算所有数在该位上1的和,如果这个和不是3的倍数,则多出的那个1肯定是由只出现过一次的那个值提供的,这样我们可以实现复杂度为O(30*n)和O(1)的空间复杂度解决该问题,这也是这篇文章中所说的第二种方法。相传这是谷歌的面试题,我给第一种做法的作者跪了,我还是没看懂。位运算真是太神奇了,许多东西需要慢慢去体会。
第一种思路的代码:
#include <stdio.h>
int getSingle(int arr[], int n)
{
int ones = 0, twos = 0 ;
int common_bit_mask;
// Let us take the example of {3, 3, 2, 3} to understand this
for( int i=0; i< n; i++ )
{
/* The expression "one & arr[i]" gives the bits that are
there in both 'ones' and new element from arr[]. We
add these bits to 'twos' using bitwise OR
Value of 'twos' will be set as 0, 3, 3 and 1 after 1st,
2nd, 3rd and 4th iterations respectively */
twos = twos | (ones & arr[i]);
/* XOR the new bits with previous 'ones' to get all bits
appearing odd number of times
Value of 'ones' will be set as 3, 0, 2 and 3 after 1st,
2nd, 3rd and 4th iterations respectively */
ones = ones ^ arr[i];
/* The common bits are those bits which appear third time
So these bits should not be there in both 'ones' and 'twos'.
common_bit_mask contains all these bits as 0, so that the bits can
be removed from 'ones' and 'twos'
Value of 'common_bit_mask' will be set as 00, 00, 01 and 10
after 1st, 2nd, 3rd and 4th iterations respectively */
common_bit_mask = ~(ones & twos);
/* Remove common bits (the bits that appear third time) from 'ones'
Value of 'ones' will be set as 3, 0, 0 and 2 after 1st,
2nd, 3rd and 4th iterations respectively */
ones &= common_bit_mask;
/* Remove common bits (the bits that appear third time) from 'twos'
Value of 'twos' will be set as 0, 3, 1 and 0 after 1st,
2nd, 3rd and 4th itearations respectively */
twos &= common_bit_mask;
// uncomment this code to see intermediate values
//printf (" %d %d \n", ones, twos);
}
return ones;
}
int main()
{
int arr[] = {3, 3, 2, 3};
int n = sizeof(arr) / sizeof(arr[0]);
printf("The element with single occurrence is %d ",
getSingle(arr, n));
return 0;
}
Output:
2
Time Complexity: O(n)
Auxiliary Space: O(1)
第二种方法是我们容易想到的,程序代码如下:
#include <stdio.h>
#define INT_SIZE 32
int getSingle(int arr[], int n)
{
// Initialize result
int result = 0;
int x, sum;
// Iterate through every bit
for (int i = 0; i < INT_SIZE; i++)
{
// Find sum of set bits at ith position in all
// array elements
sum = 0;
x = (1 << i);
for (int j=0; j< n; j++ )
{
if (arr[j] & x)
sum++;
}
// The bits with sum not multiple of 3, are the
// bits of element with single occurrence.
if (sum % 3)
result |= x;
}
return result;
}
// Driver program to test above function
int main()
{
int arr[] = {12, 1, 12, 3, 12, 1, 1, 2, 3, 2, 2, 3, 7};
int n = sizeof(arr) / sizeof(arr[0]);
printf("The element with single occurrence is %d ",
getSingle(arr, n));
return 0;
}