给你一个整数数组 nums
。如果任一值在数组中出现 至少两次 ,返回 true
;如果数组中每个元素互不相同,返回 false
。
示例 1:
输入:nums = [1,2,3,1] 输出:true
示例 2:
输入:nums = [1,2,3,4] 输出:false
示例 3:
输入:nums = [1,1,1,3,3,4,3,2,4,2] 输出:true
提示:
1 <= nums.length <= 105
-109 <= nums[i] <= 109
通过次数
803.3K
提交次数
1.5M
通过率
54.8%
开放寻址法:F = (H(key) + d) % m 式中d为增序序列,m为散列表表长。对于增量序列,分为线性探测法和平方探测法:
[1] 线性探测法: 简单来说,若发生冲突则顺序查看表中下一个单元,当查找到表尾地址时,再从表头地址开始查找。直到找到一个空闲地址或查边全表。当具有较多同义词时,会发生聚集”或堆积现象,大大降低查找效率。
[2] 平方探索法: 查找跳跃长度为线性整数的平方,即0 、 12 、(-1)2 、 22 、(-2)2 、33 、(-3)2…。该方法可以使表中存的元素相对均匀的分布,避免了堆积现象。
本题使用开放寻址法就会超时:
class Solution {
public:
const int N = 2*1e5+3, null = 0x3f3f3f3f;
int find(int x,vector<int>h){ // 查找且插入(返回位置k)
int t = (x % N + N) % N; // 加n再mod可以在c++中避免负数
while(h[t] != null && h[t]!=x){// 表中不为空且不为x
t = t + 1 % N; // 当遍历结束之后从1重新开始
}
return t;
}
bool containsDuplicate(vector<int>& nums) {
vector<int>h(N,null);
int lengthtonums = nums.size();
// k 是这个数nums的当前的位置
for(int i = 0 ; i < lengthtonums; i++){ // 插入
int k = find(nums[i],h);
if(h[k] != null) return true; //当前位置已经有数
h[k] = nums[i];
}
return false;
}
};
拉链法:
class Solution {
public:
const int N = 1e5+3;
int idx;
void insert(int x,int e[],int ne[],int h[]){// 头插法
int k = (x % N + N) % N; // 除留余法
e[idx] = x;
ne[idx] = h[k];
h[k] = idx++;
}
bool find(int k,int e[],int h[]){// 查找
int n = (k % N + N) % N;
for(int i= h[n]; i != -1; i++){
if(e[i] == k) return true;
}
return false;
}
bool containsDuplicate(vector<int>& nums) {
int h[N],e[N],ne[N];
for(int i=0; i<N; i++) h[i] = -1;
int lentonums = nums.size();
for(int i=0; i<lentonums; i++){
if(find(nums[i],e,h)) return true;
insert(nums[i],e,ne,h);
}
return false;
}
};
ac代码:
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
unordered_map<int,int>hash;
for(int i=0; i<nums.size(); i++){
if(hash.count(nums[i]) > 0) return true;
else hash[nums[i]]++;
}
return false;
}
};