《剑指Offer》题解 -- 面试题03. 数组中重复的数字

面试题03. 数组中重复的数字

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

解法一:利用Hash表判断
时间复杂度:O(n)
空间复杂度:O(n)

class Solution {
    public int findRepeatNumber(int[] nums) {
        //通过Hash表判断
        int length = nums.length;
        int[] hashArray = new int[length];
        for(int i = 0;i < length;i++){
            if(hashArray[nums[i]] != 0){
                return nums[i];
            }else{
                hashArray[nums[i]]++;
            }
        }
        return -1;
    }
}

解法二:改变数组结构(原地Hash)
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int findRepeatNumber(int[] nums) {
        //通过改变数组结构实现
        int length = nums.length;
        for(int i = 0;i < length;i++){
            while(nums[i] != i){
                if(nums[i] == nums[nums[i]]){
                    return nums[i];
                }
                int temp = nums[nums[i]];
                nums[nums[i]] = nums[i]; 
                nums[i] = temp;
            }
        }
        return -1;
    }
}

解法三:利用二分查找法
因为题目设定长度为n的数组中,所包含的为0~n-1的数字。
原本值为mid的数字前一定就有mid个数字(从0开始),每次判断数组中<=mid的数字个数,判断重复数字出现的范围。

方法可能会在某用例下错误。

比如用例中mid = i 时,恰好重复的数字存在于mid前,恰好 <= mid的个数 = (mid - start + 1) ,就会判断错误。
用例:{2,2,3,4,5}
先计算mid = (1 + 5) / 2 = 3
遍历数组发现 <= 3 的有三个数字,就会判断错误。

class Solution {
    public int findRepeatNumber(int[] nums) {
        //二分查找
        int length = nums.length;
        int start = 0;
        int end = length - 1;
        while(start <= end){
            int mid = (end - start)/2 + start;
            int count = countFun(nums,start,mid);
            if(start == end){
                if(count > 1){
                    return start;
                }else{
                    break;
                }
            }
            if(count > (mid - start + 1)){
                end = mid;
            }else{
                start = mid + 1;
            }
        }
        return -1;
    }

    public int countFun(int[] nums,int start,int end){
        int count = 0;
        int length = nums.length;
        for(int i = 0;i < length;i++){
            if(nums[i]>= start && nums[i] <= end){
                count++;
            }
        }
        return count;
    }
}
发布了30 篇原创文章 · 获赞 0 · 访问量 885

猜你喜欢

转载自blog.csdn.net/fantow/article/details/104656574