剑指Offer:数组中重复的数字(java版)

题目描述

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

使用HashSet

遍历数组,使用HashSet来存储,出现重复就直接返回true.

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;
            }else{
                set.add(numbers[i]);
            }
        }
        return false;
    }
}

选择排序

在排序对比的过程中,如果出现相等,就说明有重复数字,直接返回true

public class Solution {
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers==null || length<1) return false;
        for(int i = 1;i<length;i++){
            for(int j=i;j>0;j--){
                if(numbers[j]==numbers[j-1]){
                    duplication[0] = numbers[j];
                    return true;
                }else if(numbers[j]<numbers[j-1]){
                    swap(numbers,j,j-1);
                }
            }
        }
        return false;
    }
    public void swap(int[] arr,int i,int j){
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
}

使用一个辅助数组

使用一个byte数组(每个位置占1个字节),用numbers数组中的数字作为下标,出现过的数字,将byte[numbers[i]]设为1(原始为0)。遍历过程中,如果是1,就表明是重复出现的,直接返回true

public class Solution {
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers==null || length<1) return false;
        byte[] bt = new byte[length];
        for(int i =0;i<length;i++){
            if(bt[numbers[i]]==1){
                duplication[0]=numbers[i];
                return true;
            }
            bt[numbers[i]]=1;
        }
        return false;
    }
}

将数字移动到对应的坐标

因为数组长度为n,而数字为0-n-1,所以以当前的数字numbers[i]为下标,都不会越界。
因此,把number[i]移动到numbers[numbers[i]]位置上,表示坐标i与该坐标上的数字numbers[i]是相等的。
利用这个方法,将每个数字都移动到相对应的坐标位置,移动时如果对应位置上的数已经等于了numbers[i],就表示出现了重复的数字。

public class Solution {
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers==null || length<1) 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[] arr ,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

在相应位置做标记

跟上一种方法类似,用当前的数做坐标index=numbers[i],在相应的位置numbers[index]做标记,减去length(变为了负数)
如果要做标记的位置,已经是负数,表明出现了重复的数字。
注意:在遍历到numbers[index]位置时,如果这个位置被做了标记,那么要判断原来这个位置上的数字所对应位置的状态,需要加上length才能得到原来的数字。

public class Solution {
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers==null || length<1) return false;
        for(int i=0;i<length;i++){
            int index = numbers[i];
            if(index<0){
                index+=length;
            }
            if(numbers[index]<0){
                duplication[0]=index;
                return true;
            }
            numbers[index]-=length;
        }
        return false;
    }
    public void swap(int[] arr ,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值