找出数组中的重复数字-Java实现

3. 找出数组中的重复数字

给定一个长度为n的数字,所有的数都在0~n-1的范围内,数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次,请找出数组中任意一个重复的数字。例如:输入长度为7的数组{2, 3, 1, 0, 2, 5, 3},那么对应的输出是重复的数字2或者3

注意题:只需要找出任意一个,下面我的部分方法会把全部的重复数字找出来,看看就得了

重点在于第二个方法,其余的都是蛇皮

分析:

  1. 我们第一想到的一定是对这个数组排序然后遍历这个数组,检查到重复的数字的时候输出这个数字。排序一个长度为n的数组需要O(nlogn)的时间。

    /**
     * 首先我们最先想到的应该是将这个数组排序后如何遍历这个数组,然后检测出重复的数字
     */
    public static void test(int[] a, int len) {
       // 这个方法没有对数据的有效性进行检测,有需要的自己添加
    	Arrays.sort(a);
        for (int i = 0; i < len - 1; i++) {
            if (a[i] == a[i + 1]) {
                System.out.print(a[i] + " ");
                int j = i + 1;
                for (j = i + 1; j < len - 1; j++) {
                    if (a[j] != a[i]) {
                        break;
                    }
                }
                i = j-1;
            }
        }
        System.out.println();
    }
    
  2. 第二,我们可以利用哈希表的特性,从头到尾扫描这个数组,每次O(1)检测这个数字是不是在哈希表里了,如果没有,那就把它加入哈希表,如果有的话,那么这个数就是重复的;

    public static boolean duplicate(int[] a, int len) {
        if (a == null || len <= 0) {
            return false;
        }
        for (int i = 0; i < len; i++) {
            // 参数有效性检测
            if(a[i] < 0 || a[i] > len-1){
                return false;
            }
            while(a[i] != i){
                if(a[i] == a[a[i]]){
                    System.out.println(a[i]);
                    return true;
                }
                else{
                    int temp = a[i];
                    a[i] = a[temp];
                    a[temp] = temp;
                }
            }
        }
        return false;
    }
    

    上述代码分析:

    • 这个数组的所有数据都是在 0~n-1之间,假设我们按从小到大的方式进行排序,如果没有重复的数字的话,那么下标为i的数字m必定等于i。所以我们比较下标为i的数字m,如果m = i,那么接着比较下一个数字;如果不等于的话,就拿它和第m个数字进行比较,如果它和第m个数字相等,那么就找到了一个重复的数字(该数字在下标为i和m的位置都出现了),如果它和第m个数字不相等,就交换着两个数,把m放在它应该在的位置上,接下来重复这个步骤。

    • 拿上述例子做分析 {2,3,1,0,2,5,3}

      • i=0时,i != a[i],所以比较a[a[i](1)和a[i](2)的值(括号内为数据),比较结果不相等,交换位置,现在数组成了{1, 3, 2, 0, 2, 5, 3}
      • 此时i还是等于0,而 a[i] != i,重复上面的步骤,得到不相等,交换位置,这个数组现在变成{3, 1, 2, 0, 2, 5, 3 }
      • 此时i还是为0, 而 a[i](3) != i(0),重复上面的步骤,不相等,交换位置,数组变成{0, 1, 2, 3, 2, 5, 3}
      • 此时下标还是为0,但是a[i](0) = i(0),i向后移
      • 依次扫描 1, 2, 3,都是满足的
      • 当i等于4的时候,此时a[4] = 2, 而a[a[i]] = 2 ,这个时候就找到了重复的数字2了,好了,程序结束。

      这个方法的时间复杂度是O(n),所有的操作都是在原输入数组上进行的,不需要额外的内存

  3. 我利用了java的hashSet不允许插入重复数据的方式做了以下实现:

    	// 这是我利用java的hashSet实现的
        public void test2(int[] a, int len) {
            // 这个方法没有对数据的有效性进行检测,有需要的自己添加
            HashSet hashSet = new HashSet();
            for (int i = 0; i < len; i++) {
                boolean add = hashSet.add(a[i]);
                if (add == false) {
                    System.out.print(a[i] + " ");
                }
            }
            System.out.println();
        }
    

    可以了解一下,但是只是些没用的

  4. 这个方法是我利用空间换时间来操作的

        public static void test3(int[] a, int len) {
            // 这个方法没有对数据的有效性进行检测,有需要的自己添加
            // 这个数组默认全为-1
            int[] b = new int[len];
            for (int i = 0; i < len; i++) {
                b[i] = -1;
            }
            // 循环遍历原数组,如果b[a[i]] 的位置存了数据不为-1的话 说明这个数在之前已经出现过了,所以重复
            for (int i = 0; i < len; i++) {
                if (b[a[i]] != -1) {
                    System.out.println(a[i]);
                }
                b[a[i]] = a[i];
            }
            // 原理就是将这个数组中的每一个数依次放到对应位置上去,如果之前有了,那么就是重复,如果没有,那就放
        }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值