217. Contains Duplicate(存在重复元素)

本文详细解析了LeetCode上“含有重复元素”题目,提供了两种解决方案:一是使用计数排序思想,二是利用位操作结合byte数组存储,探讨了各种方法的优缺点及适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接: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;
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值