Java 实现数组中重复的数字

本文介绍三种高效查找数组中重复数字的方法:排序法、使用Map计数法及原地置换法。适用于数组元素范围限定的情况。

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

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

代码

解法一

先排序,这样重复的数字就会前后相邻,然后遍历数组,只要当前数字和下一个数字相等,则说明该数字重复,时间复杂度因排序而定,O(nlogn),但是存在的问题是,如果重复的数量大于2,则会多次输出。

    public static void duplicateInt(int[] array) {
        if (array == null) {
            return;
        }
        // 存在重复数字,起码有两个以上的数字才可以
        int len = array.length;
        if (len < 2) {
            return;
        }
        for (int i = 0; i < len; i++) {
            // 数字中的数字范围在0到len-1之间,否则就认为是个错误的数组,不考虑重复数字问题
            if (array[i] < 0 || array[i] > len - 1) {
                return;
            }
        }
        // 排序 Arrays.sort(array)
        sort(array, 0, len - 1);
        for (int i = 0; i < len - 1; i++) {
            if (array[i] == array[i + 1]) {
                System.out.print(array[i] + " ");
            }
        }
        return;
    }

    /**
     * 快排
     * @param array
     * @param lo
     * @param hi
     */
    public static void sort(int[] array,int lo ,int hi){
        if(lo>=hi){
            return ;
        }
        int index=partition(array,lo,hi);
        sort(array,lo,index-1);
        sort(array,index+1,hi);
    }

    public static int partition(int []array,int start,int end){
        // 固定的切分方式
        int key = array[start];
        while(start < end){
            // 从后半部分向前扫描
            while(end > start && array[end] >= key){
                end--;
            }
            array[start] = array[end];
            // 从前半部分向后扫描
            while(start < end && array[start] < key){
                start++;
            }
            array[end]=array[start];
        }
        array[start]=key;
        return end;
    }

解法二

借助Map,因为只需遍历一次,利用Map来记录每个数字出现的次数,时间复杂度会降到0(n),但是会额外开辟O(n)的Map空间。好处是可以明确知道每个数字的重复次数。

    public static void duplicateInt2(int[] array) {
        if (array == null) {
            return;
        }
        // 存在重复数字,起码有两个以上的数字才可以
        int len = array.length;
        if (len < 2) {
            return;
        }
        for (int i = 0; i < len; i++) {
            // 数字中的数字范围在0到len-1之间,否则就认为是个错误的数组,不考虑重复数字问题
            if (array[i] < 0 || array[i] > len - 1) {
                return;
            }
        }
        Map<Integer, Integer> map = Maps.newHashMap();
        for (int i = 0; i < len; i++) {
            if (map.containsKey(array[i])) {
                map.put(array[i], map.get(array[i]) + 1);
            } else {
                map.put(array[i], 1);
            }
        }
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            if (entry.getValue() > 1) {
                System.out.print(entry.getKey() + " ");
            }
        }
        return;
    }

解法三

题目中明确指出n个数字,其取值范围在0到n-1之间,所以可以认为

  • 如果都不相等,则数组下标总能找到和其一致的数字
  • 如果存在重复的,则某些数组下标应有一个以上的数字与之相一致

所以我们通过找与下标一致的数字,如果当前下标中放得数字与下标不一致,则看该数字对应的下标中的数字是否和当前下标中的数字是否一致

  • 若一致,则输出,并找下一个重复数字
  • 若不一致,则交换两个下标对应的数字,并重复此过程

这样,数字都落在与其一致的下标中,只有重复的数字,会落在其他与其不一致的(重复次数-1)下标中

    public static void duplicateInt3(int[] array) {
        if (array == null) {
            return;
        }
        // 存在重复数字,起码有两个以上的数字才可以
        int len = array.length;
        if (len < 2) {
            return;
        }
        for (int i = 0; i < len; i++) {
            // 数字中的数字范围在0到len-1之间,否则就认为是个错误的数组,不考虑重复数字问题
            if (array[i] < 0 || array[i] > len - 1) {
                return;
            }
        }
        
        // 比如 {2, 3, 1, 0, 2, 5, 3}
        // array[0] = 2,不一致,array[2] = 1, 不相等,则交换,得到 {1, 3, 2, 0, 2, 5, 3}
        // array[0] = 1,不一致,array[1] = 3, 不相等,则交换,得到 {3, 1, 2, 0, 2, 5, 3}
        // array[0] = 3,不一致,array[3] = 0, 不相等,则交换,得到 {0, 1, 2, 3, 2, 5, 3}
        // array[0] = 0,一致,现在下标0中存放了预期一致的数字,结束下标0的操作
        // array[1] = 1,一致,现在下标1中存放了预期一致的数字,结束下标1的操作
        // array[2] = 2,一致,现在下标2中存放了预期一致的数字,结束下标2的操作
        // array[3] = 3,一致,现在下标3中存放了预期一致的数字,结束下标3的操作
        // array[4] = 2,不一致,array[2] = 2,相等输出结果,无需交换,结束下标4的操作,此时 {0, 1, 2, 3, 2, 5, 3}
        // array[5] = 5,一致,现在下标5中存放了预期一致的数字,结束下标5的操作
        // array[6] = 3,不一致,array[3] = 3,相等输出结果,无需交换,结束下标4的操作,此时 {0, 1, 2, 3, 2, 5, 3}
        for (int i = 0; i < len; i++) {
            while (array[i] != i) {
                if (array[i] == array[array[i]]) {
                    System.out.print(array[i] + " ");
                    break;
                } else {
                    int temp = array[i];
                    array[i] = array[temp];
                    array[temp] = temp;
                }
            }
        }
        return;
    }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值