一、哈希
哈希,时间复杂度O(n),空间复杂度O(n),适用范围更广。
思路:
哈希存入,查找是否存在,查找过程时间复杂度O(1)
#include <unordered_map> class Solution { public: bool duplicate(int numbers[], int length, int* duplication) { unordered_map<int, int> hash_map; for (int i = 0; i < length; i++) { auto it = hash_map.find(numbers[i]); if (it != hash_map.end()) { //found *duplication = numbers[i]; return true; } else { //not found hash_map[numbers[i]] = i; } } return false; } };
二、拿现有数组作查找log
时间复杂度O(n),空间复杂度O(1),只适用于这些数都小于n的情况 思路:
所有数都在n内,找第一组重复的值。
那么在第一组重复的值的第二个值之前,所有的数字都只出现了一次。
每遇到一个数x,都把以 x 为下标的数 array[x] + n,由于x不重复,以x为下标的元素也是不重复的
当然,这样会把后面路上的元素+n,所以在考虑遇到的x时,如果 x>n 要将 x-=n ,减的是副本,所以不影响找到目标。
当重复时,即想把一个数+n时,发现它已经>n了,这就是第一组。
最终效果就是:
突出的元素(+n)就代表已经已经出现过,用来当访问记录log。把从哈希表中查找,转换到了在本数组查找
改进点:
x + n,如果 n > INT_MAX/2 就可能会导致溢出
改成 x - n :
假设n = INT_MAX
[0 , INT_MAX - 1] ---> [-INT_MAX , -1],既不溢出,也没有歧义
那么在第一组重复的值的第二个值之前,所有的数字都只出现了一次。
每遇到一个数x,都把以 x 为下标的数 array[x] + n,由于x不重复,以x为下标的元素也是不重复的
当然,这样会把后面路上的元素+n,所以在考虑遇到的x时,如果 x>n 要将 x-=n ,减的是副本,所以不影响找到目标。
当重复时,即想把一个数+n时,发现它已经>n了,这就是第一组。
最终效果就是:
突出的元素(+n)就代表已经已经出现过,用来当访问记录log。把从哈希表中查找,转换到了在本数组查找
改进点:
x + n,如果 n > INT_MAX/2 就可能会导致溢出
改成 x - n :
假设n = INT_MAX
[0 , INT_MAX - 1] ---> [-INT_MAX , -1],既不溢出,也没有歧义
class Solution { public: bool duplicate(int numbers[], int length, int* duplication) { for(int i = 0; i < length; i++){ int value = numbers[i]; if(value < 0) //路上被减小了的元素 value += length; //对副本操作,不影响找到目标 if(numbers[value] < 0){ //发现以value为下标的数已经小于0了,表示这是已经访问过的。 *duplication = value; return true; } numbers[value] -= length; //去以value为下标的位置,-length } return false; } };