先看看这个题目:某整形数组中除了两个单身整数外, 其余的整数都是成对出现的, 利用C代码求出这两个单身整数。 要求: 时间复杂度o(n), 空间复杂度o(1).
我们先用最傻瓜的方式来做吧:
#include <iostream> using namespace std; // 时间复杂度为o(n^2), 空间复杂度为o(1), 不符合要求 void findSoleNumbers(int a[], int n, int &e1, int &e2) { int i = 0; int j = 0; int continueFlag = 0; // 控制外层for, 推断是否过滤当前整数 int numberFlag = 0; // 标志第一个、第二个单身整数 for(i = 0; i < n; i++) { continueFlag = 0; for(j = 0; j < n; j++) { if(j != i && a[j] == a[i]) { continueFlag = 1; break; } } if(1 == continueFlag) // 该整数是成双成对的。 过滤掉 { continue; } // 可怜的单身整数 if(0 == numberFlag++) { e1 = a[i]; } else { e2 = a[i]; } } } int main() { { int a[] = {1, 5, 3, 5, 1, 2}; int n = sizeof(a) / sizeof(a[0]); int e1 = 0; int e2 = 0; findSoleNumbers(a, n, e1, e2); cout << e1 << endl; cout << e2 << endl; cout << "--------------------------" << endl; } { int a[] = {1, 1, 2, 5, 4, 5, 2, 4, 3, 0}; int n = sizeof(a) / sizeof(a[0]); int e1 = 0; int e2 = 0; findSoleNumbers(a, n, e1, e2); cout << e1 << endl; cout << e2 << endl; cout << "--------------------------" << endl; } return 0; }结果为:
3
2
--------------------------
3
0
--------------------------
上面程序时间复杂度不满足题目要求。
当然, 有的朋友可能会想到排序, 思路是能够, 可是, 时间复杂度依旧不是o(n), 所以, 排序法我就不介绍了。
因为数组中整数的范围并没有给出。 所以, 也不太适合用计数的方法来做。 那怎么办呢? 假如该题目中的整形数组中仅仅有一个单身整数。 那也好办, 例如以下:
#include <iostream> using namespace std; // 时间复杂度为o(n), 空间复杂度为o(1), 不符合要求 void findSoleNumber(int a[], int n, int &e) { e = 0; int i = 0; for(i = 0; i < n; i++) { e ^= a[i]; } } int main() { { int a[] = {1, 5, 3, 5, 1}; int n = sizeof(a) / sizeof(a[0]); int e = 0; findSoleNumber(a, n, e); cout << e << endl; cout << "--------------------------" << endl; } { int a[] = {0, 5, 1, 5, 1, 2, 2}; int n = sizeof(a) / sizeof(a[0]); int e = 0; findSoleNumber(a, n, e); cout << e << endl; cout << "--------------------------" << endl; } return 0; }结果:
3
--------------------------
0
--------------------------
上面的方法虽然没有彻底解决这个问题, 但已经提供了思路的雏形了。 以下。 我直接给出可行的方法。 代码本身就是最好的解释, 所以不再解释。 代码例如以下:
#include <iostream> using namespace std; // 在num的二进制中查找第一个出现1的位置 int findFirstBitEquOne(int num) { int bitIndex = 0; while(bitIndex < 32 && 0 == (num & 1)) { num >>= 1; bitIndex++; } return bitIndex; } // 推断num二进制的bitIndex位上的数是否为1 bool isBitOne(int num, int bitIndex) { return ( (num >>= bitIndex) & 1); } // 时间复杂度为o(n), 空间复杂度为o(1) void findSoleNumbers(int a[], int n, int &e1, int &e2) { e1 = 0; e2 = 0; int i = 0; int result = 0; for(i = 0; i < n; i++) { result ^= a[i]; // 最后的result肯定是两个单身整数的异或值 } int bitIndex = findFirstBitEquOne(result); for(i = 0; i < n; i++) { // 对于每个整数, 依据isBitOne原则进行分组, 两个单身整数必定落在不同的组中, 而成双成对的整数必定落在同一组中 if(isBitOne(a[i], bitIndex)) // 组1 { //cout << "debug1: " << a[i] << endl; e1 ^= a[i]; } else // 组2 { //cout << "debug2: " << a[i] << endl; e2 ^= a[i]; } } } int main() { { int a[] = {1, 5, 3, 5, 1, 2}; int n = sizeof(a) / sizeof(a[0]); int e1 = 0; int e2 = 0; findSoleNumbers(a, n, e1, e2); cout << e1 << endl; cout << e2 << endl; cout << "--------------------------" << endl; } { int a[] = {1, 1, 2, 5, 4, 5, 2, 4, 3, 0}; int n = sizeof(a) / sizeof(a[0]); int e1 = 0; int e2 = 0; findSoleNumbers(a, n, e1, e2); cout << e1 << endl; cout << e2 << endl; cout << "--------------------------" << endl; } return 0; }结果例如以下:
3
2
--------------------------
3
0
--------------------------
异或的思路。 非常巧妙, 以后要注意。 好了。 本文先到此为止。