题目链接:https://leetcode.com/problems/contains-duplicate/
Given an array of integers, find if the array contains any duplicates.
Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct.
Example 1:
Input: [1,2,3,1]
Output: true
Example 2:
Input: [1,2,3,4]
Output: false
Example 3:
Input: [1,1,1,3,3,4,3,2,4,2]
Output: true
思路:
有种借用hashmap和set的我就不介绍了,如果面试官在问你这个问题的时候估计他也不想听到这种答案,
有一道题和这道题看起来很像,最后是用位运算解决的 传送门。
不过这道题我想了好久,发现那道题利用的异或运算在这道题的场景下并不适用。
后来没办法只好用空间换时间,用到了计数排序的思路。还好这道题只是整形,不然可能会很费内存。
思路一:
Runtime: 2 ms, faster than 99.37% of Java online submissions for Contains Duplicate.
Memory Usage: 41.7 MB, less than 98.60% of Java online submissions for Contains Duplicate.
class Solution {
public boolean containsDuplicate(int[] nums) {
if(nums==null||nums.length==0)
return false;
int max=Integer.MIN_VALUE;
int min=Integer.MAX_VALUE;
for(int i=0;i<nums.length;i++){
max=Math.max(max,nums[i]);
min=Math.min(min,nums[i]);
}
int[] array=new int[max-min+1];
for(int i=0;i<nums.length;i++){
array[nums[i]-min]++;
if(array[nums[i]-min]==2)
return true;
}
return false;
}
}
****************************************debug专用分割线********************************************************************************
最后才发现,网站给的测试数据不够,这样的计数排序竟然能够通过,
比如以下数据 [2147483647,-2147483648,2147483647,-2147483648]
max=2147483647, min=-2147483648
而max-min的值已经超出了int的范围了,在int[] array=new int[max-min+1]会报错的,因为size只能为int类型,
从StackOverflow上面看到的
The size of an array can only be an int
. That is you, can not create arrays that are larger than Integer.MAX_VALUE (2147483647), probably a few elements less (depending on the VM).
这个问题是我在写219题时发现的,他的一个测试数据就是这样的
然后我又去217题看能不能看到具体的测试用例,18个测试用例看不到,于是我测试了一下是否存在
max=Integer.MAX_VALUE ,min=Integer.MIN_VALUE的情况,测试代码如下:
我在原来通过的代码里额外添加了两行,在星标注释处。
class Solution {
public boolean containsDuplicate(int[] nums) {
if(nums==null||nums.length==0)
return false;
int max=Integer.MIN_VALUE;
int min=Integer.MAX_VALUE;
for(int i=0;i<nums.length;i++){
max=Math.max(max,nums[i]);
min=Math.min(min,nums[i]);
}
if(max-min+1>Integer.MAX_VALUE)//******************
return false;//****************
int[] array=new int[max-min+1];
for(int i=0;i<nums.length;i++){
array[nums[i]-min]++;
if(array[nums[i]-min]==2)
return true;
}
return false;
}
}
结果还是通过了,然后我把第二行的return false 改为true ,结果仍然是通过的。
说明那18个测试用例里面并不包含 max-min+1>Integer.MAX_VALUE这种情况的 ,平台的数据应该再添加才行。
最后,发现了leetcode的测试数据也是包含漏洞的,
思路二:
这个方法是用位操作结合 byte类型数组存储,缺点是消耗的内存太大,如果输入数据很大的话会Memory Limit Exceeded
比如[-1200000005,-1200000005],这个数据就无法通过。
我的测试代码如下:
class Solution {
public boolean containsDuplicate(int[] nums) {
if(nums==null||nums.length==0)
return false;
byte[] mark = new byte[Integer.MAX_VALUE];//每个byte八位,可以存储八个num
for(int num:nums){
int index=num/8;//计算出要存储到哪个byte格子里面
int shift=num%8;//计算出存在格子的第几位
int check=1<<shift;//如果是重复数字的话那么具体 byte格子 该数字对应位置为1
if((check&mark[index])!=0)
return true;
mark[index]|=check;
}
return false;
}
}
总结:
上面提供了两种解决这类题的思路,比较难过的是,这两种思路难以解决数值较大的情况。
最后只好用hashmap set来解决这个问题了,或者可以遍历两遍。
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<Integer>();
for(int i : nums)
if(!set.add(i))// if there is same
return true;
return false;
}
}