217.Contains Duplicate(存在重复元素)
在看到这一个问题的时候我的第一想法是,如果使用双重循环去遍历每一个元素是否存在与之相同的元素不就能将问题解决吗?于是我写出了下面的代码:
bool containsDuplicate(int* nums, int numsSize) {
for(int i = 0; i< numsSize; i++){
for(int j = i+1; j<numsSize; j++){
if(nums[i]==nums[j]){
return 1;
}
}
}
return 0;
}
但是这种算法的时间复杂度是O(n2)O(n^2)O(n2)当数组的规模特别大时就会特别耗费时间,所以不出我所料的Time Limit Exceeded了。
既然这种不行,那我们就需要去寻找如何去利用更短的时间去查找相同的元素了,我们想一想我们是不是可以建立一个特别大的数组p,然后元素的值nums[i]作为下标,在数组中使用元素p[nums[i]]来存储nums[i]的出现次数,这样在之后我们就能够先遍历一遍nums[i]找出每一个元素的出现次数,然后遍历数组p产看是否存在出现次数超过1的元素。
上面这种方法在理论上可行,但是因为nums[i]的取值范围是特别大的,如果我们要建立一个这样的数组p,这个数组p就会特别大,显然这种方法的空间效率特别低。
那么我们能不能优化一下数组的存储方式,来让空间效率变得可以接受?我们首先来看一下对于nums中nums[i]元素的取值最多有numsSize种,也就是说我们理论上只需要numsSize个存储单元就能够完成数组p的存储,所以我们现在的主要目标就是将nums种的元素建立一个映射,来使这些元素映射到0 ~ numsSize-1之间,说到这,你有没有想到一种运算可以将元素的值映射到0 ~ numsSize之间,那就是取余运算,所以我们可以先通过取余运算建立一个映射,但是这一种映射会将一些余数相同的数映射到一类中,所以p数组中p[i]中存储的元素表示的是余数为i的元素出现的次数,而不是i这一个元素出现的次数,所以我们还要在p数组中p[i]存储nums中余数为i的元素,这样建立好之后,我们在p中查找出现次数大于1的元素,检查其中元素是否存在相等的情况。
这样我们就能够完成相同元素的判别,而且这种算法在一般情况下时间复杂度为O(n),最坏情况下为O(n²).
算法画出图示为:





然后检查出现次数大于1的元素的值是否相等,这一步可以在添加元素到p中的时候进行,这时候进行操作就行了,综上我们可以写出代码如下:
struct ListNode1{
int val;
int index;
struct ListtNode1 *next;
};
struct ListNode2{
int count;
struct ListNode1 *val;
};
int containsDuplicate(int* nums, int numsSize) {
struct ListNode2 * p = (struct ListNode2 *)malloc(sizeof(struct ListNode2)*numsSize);
for(int i = 0; i<numsSize; i++){
p[i].count = 0;
p[i].val =NULL;
}
for(int i = 0; i<numsSize; i++){
int x = nums[i]%numsSize;
if(x<0){
x+= -1*(x/numsSize-1)*numsSize;
}
p[x].count+=1;
struct ListNode1 *q = (struct ListNode1 *)malloc(sizeof(struct ListNode1));
q->val = nums[i];
q->next = NULL;
if(p[x].val!=NULL){
struct ListNode1 *s;
s = p[x].val;
while(s->next!=NULL){
if(s->val==q->val){
return 1;
}
s = s->next;
}
if(s->val==q->val){
return 1;
}
s->next = q;
}else{
p[x].val = q;
}
}
return 0;
}
运行结果截图:

219. Contains Duplicate II(存在重复元素 II)
这一个问题与217. Contains Duplicate(存在重复元素)问题的主要差别在于,此问题需要额外判断一个i-j<=k,将此条件加上就行了,
代码如下:
struct ListNode1{
int val;
int index;
struct ListtNode1 *next;
};
struct ListNode2{
int count;
struct ListNode1 *val;
};
int containsNearbyDuplicate(int* nums, int numsSize, int k) {
struct ListNode2 * p = (struct ListNode2 *)malloc(sizeof(struct ListNode2)*numsSize);
for(int i = 0; i<numsSize; i++){
p[i].count = 0;
p[i].val =NULL;
}
for(int i = 0; i<numsSize; i++){
int x = nums[i]%numsSize;
if(x<0){
x+= -1*(x/numsSize-1)*numsSize;
}
p[x].count+=1;
struct ListNode1 *q = (struct ListNode1 *)malloc(sizeof(struct ListNode1));
q->val = nums[i];
q->index = i;
q->next = NULL;
if(p[x].val!=NULL){
struct ListNode1 *s;
s = p[x].val;
while(s->next!=NULL){
if(s->val==q->val&&q->index-s->index<=k){
return 1;
}
s = s->next;
}
if(s->val==q->val&&q->index-s->index<=k){
return 1;
}
s->next = q;
}else{
p[x].val = q;
}
}
return 0;
}
运行结果如下:

307



被折叠的 条评论
为什么被折叠?



