题目:
给定一个整数数组,判断是否存在重复元素。
如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。
原题地址
示例 1:
输入: [1,2,3,1]
输出: true
示例 2:
输入: [1,2,3,4]
输出: false
示例 3:
输入: [1,1,1,3,3,4,3,2,4,2]
输出: true
此题比较简单,主要在于思路。
思路一:
最简单的方法是嵌套循环,每个数依次与它前面的数进行比较,相等则返回true。
private static boolean containsDuplicate(int[] nums) {
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] == nums[j]) {
return true;
}
}
}
return false;
}
这种解法的时间复杂度是 O(n2),时间花费较久。
思路二:
换一种思路来,如果数组本身是有序的,那么重复的元素必定处于相邻上,那么只要比较相邻元素就行了。
public boolean containsDuplicate(int[] nums) {
Arrays.sort(nums);
for (int i=0; i < nums.length - 1; i++){
if(nums[i] == nums[i+1]){
return true;
}
}
return false;
}
思路三:
利用Set元素不重复的性质来去重。
public boolean containsDuplicate(int[] nums) {
Set<Integer> numSet = new HashSet<>(nums.length);
for (int i: nums){
if(numSet.contains(i)){
return true;
}
numSet.add(i);
}
return false;
}
思路四:
看了下LeetCode上耗时最短的解法,思路是利用boolean数组和&操作符。
&操作运算规则:将两个数都转为二进制,然后从高位开始比较,如果两个数都为1则为1,否则为0。
如:129&128.
129转换成二进制就是10000001,128转换成二进制就是10000000。从高位开始比较得到,得到10000000,即128.
public boolean containsDuplicate(int[] nums) {
if (nums.length < 1 || nums[0] == 237384 || nums[0] == -24500)
return false;
boolean[] bc = new boolean[1024];
for (int num : nums) {
/*1023的二进制为1111111111,num&1023的结果为num
如果对应位置已经为true,说明存在相同数字,返回true*/
if (bc[num & 1023])
return true;
//将boolean数组中对应位置设为true
bc[num & 1023] = true;
}
return false;
}
但是此解法存在问题,上面说num&1023的结果为num,只限于num<=1023的情况,当num>1023时(比如1024),1024&1023结果为0,此时如果数组为[0,1024],0&1023和0&1024结果都为0,此解法返回true,显然与预期不符。因此这个解法只适用于nums中的元素<=1023的情况。