剑指offer面试题3-数组中重复数字

一.题目描述

找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

二.题目解答

有三种解法:

package exercise1;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * offer03
 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。
 数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。
 请找出数组中任意一个重复的数字。

 */
public class Solution {
    public int findRepeatNumber(int[] nums) {
        /*哈希表
        * 时间复杂度O(n),空间复杂度O(n)
        * */
        Set set = new HashSet();
        for (int i = 0; i < nums.length; i++) {
            boolean flag = set.add(nums[i]);
            if(!flag){
                return nums[i];
            }
        }
        return -1;
    }
    public int findRepeatNumber1(int[] nums) {
        /*
         * 时间复杂度O(nlogn),空间复杂度O(1)
         * */

        Arrays.sort(nums);
        for (int i = 0; i < nums.length - 1; i++) {
            if(nums[i] == nums[i + 1]){
                return nums[i];
            }
        }
        return -1;
    }
    public int findRepeatNumber2(int[] nums) {
        /*原地置换算法
         * 时间复杂度O(n),空间复杂度O(1)
         * */

        int temp;
        for (int i = 0; i < nums.length; i++) {
            int actual = nums[i];
            while(actual != i){
                //如果i位置上的数字actual不是预期的i,那么说明下标为actual位置上的数字也有可能不是预期的actual
                //(当不存在重复元素时肯定不是)
                //于是交换,当出现重复元素时,交换过程中必有actual == nums[actual]相等的时刻
                if(actual == nums[actual]){
                    return actual;
                }
                temp = actual;
                nums[i] = nums[actual];
                nums[actual] = temp;
                actual = nums[i];
            }
        }
        return -1;
    }
}

注:还有一种方法是二分查找,思想是

假设10个数0-9,start=0,end=9,mid=4
 * 统计0-4的5个数在10个数中出现的次数,如果0-4不存在重复,则次数是5,只需要将目标锁定在mid+1--end的数。
 * 如果0-4出现重复,则次数将大于5,这时将目标锁定在start,mid中。
 * 以此类推
package exercise1;

/**
 * offer03,二分法找重复元素,时间复杂度O(nlogn),空间复杂度O(n)
 * 缺点是不能确保100%能找出-比如统计1-2范围内count=2,我们无法确定是每个数字各出现一次还是某个数字出现了两次
 */
public class Solution1 {
    public static void main(String[] args) {
        int[] arr = new int[]{0, 1, 2, 0, 4, 5, 6, 7, 8, 9};
        System.out.println(new Solution1().findRepeatNumber(arr));
    }
    public int findRepeatNumber(int[] nums) {
        //0-n-1,长度n
        return getDuplication(nums,nums.length);
    }

    private int getDuplication(int[] nums, int length) {
        if(nums == null || length <= 0){
            return -1;
        }
        int start = 0;
        int end = length -1;
        while(end >= start){
            //运算符优先级,((end - start) >> 1)
            int middle = ((end - start) >> 1) + start;
            int count = getCount(nums,length,start,middle);
            if(end == start){
                if(count > 1){
                    return start;
                }
            }
            if(count > middle - start + 1){

                end = middle;
            }else{

                start = middle + 1;
            }

        }
        return -1;
    }

    private int getCount(int[] nums, int length, int start, int end) {
        if(nums == null || length <= 0){
            return 0;
        }
        int count = 0;
        for (int i = 0; i < length; i++) {
            if(nums[i] >= start && nums[i] <= end){
                count++;
            }
        }
        return count;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值