数组中重复的数字

题目描述

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
返回描述:
如果数组中有重复的数字,函数返回true,否则返回false。
如果数组中有重复的数字,把重复的数字放到参数duplication[0]中。(ps:duplication已经初始化,可以直接赋值使用。)

思路分析

最暴力的解法:对数组进行排序,排序后的数组,比较两个相邻的数是否相等 ,排序一个长度为n的数组为O(nlogn).该方法对原数组进行了修改

利用哈希表的不可重复性:对数组遍历一边,如果表中存在这个元素,则记录dup中,返回true,否则添加 时间复杂度O(n),空间复杂度,是一个大小为O(n)大小的哈希表 ,对原数组没有修改,且能知道第一次出现重复的值

import java.util.*;
public class Solution {
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers==null||length<0){
            return false;
        }
       HashSet<Integer> set= new HashSet();
       for(int i=0;i<length;i++){
           if(set.contains(numbers[i])){
               duplication[0]=numbers[i];
               return true;
           }
           set.add(numbers[i]);
       }
       return false;
    }
}

上述都没有用到题目中所给的所有数字都在0到n-1的范围内这个条件,思考一下如果数组没有重复值,那么长度为n的数组中的值肯定能和0~n-1这些数值中的值一一对应起来,所以,我们可以让原始数组的每一个下标都对应下标的值,如果在交换的过程中发现,发现与下标对应的值相等则说明找到

public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers==null||length<=0){
            return false;
        }
        for(int i=0;i<length;i++){
            while(numbers[i]!=i){
                if(numbers[i]==numbers[numbers[i]]){
                    duplication[0]=numbers[i];
                    return true;
                }
                swap(numbers,i,numbers[i]);
            }
        }

        return false;
    }


    public void swap(int[] nums,int i,int j){
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }

注意,此方法只能找到任意一个重复的值,但找不到第一个重复的值,(例如,6,3,2,0,2,5,0)该程序输出重复的值0但正确应该是 2,所以要看清楚题目

拓展:在一个长度为n+1的数组里的所有数字都在1到n的范围内。所以数组至少有一个数字是重复的。请找出数组中任意一个重复的数字。但不能修改数组。

可以使用O(n)的额外空间,像上述那样解决问题 。下面是避免使用O(n)的辅助空间

  /**
     * 在一个长度为n+1的数组里的所有数字都在1到n的范围内。所以数组至少有一个数字是重复的。请找出数组中任意一个重复的数字。但不能修改数组
     */

    //思路:在数字范围1...n上二分,对每次的左半部分 若果,数组中的数字在这个范围上个数小于二分长度,那右半部分一定有重复的数字,如果大于二分长度
    //一定在左半部分,依次递归,直到不能再分时结束递归
    int dup[] = new int[1];
    public int getDuplication(int[] nums, int length,int start, int end) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        if (start == end) {
            dup[0] = start;
            return start;
        }
        int mid = start + ((end - start) >> 1);

        int i = CountRange(nums, length, start, mid);//每次递归都计算出左范围,数组中有的个数

        if (i > (mid - start + 1)) {//左边这个范围上一定有重复的  继续递归
            getDuplication(nums, length, start, mid);
        } else {//
            getDuplication(nums, length, mid+1, end);
        }

        return dup[0];
    }
    
    /*
    数组在这个start ...end长度范围上有多少个值
     */
    public int CountRange(int[] nums, int length, int start, int end) {
        int count=0;
        if (nums == null) {
            return -1;
        }
        for (int i = 0; i < length; i++) {
            if (nums[i] >= start && nums[i] <= end) {
                count++;
            }
        }
        return count;

    }
posted @ 2020-11-04 17:31  清风5438  阅读(129)  评论(0编辑  收藏  举报