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

题目

找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1
的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入: [2, 3, 1, 0, 2, 5, 3] 输出:2 或 3
限制:2 <= n <= 100000

算法思路

本题思路大致分为三种。
方法一:使用哈希表来记录,依次遍历,如果哈希表中没有该数字,就加入哈希集中,存在就说明该数字重复了,返回即可。该方法时间和空间复杂度都是O(N)。
方法二:排序,再依次遍历,存在相邻两个数字相等,返回该数字即可。该方法时间复杂度为O(NlogN),即排序的复杂度,空间复杂度为O(1)。
方法三:原地置换,首先这道题目中表明了数组中的数字的范围在**(0 ~ n-1)**,而数组的长度为n,通过索引来记录则不会存在数组越界。
如果没有重复数字,那么正常排序后,数字i应该在下标为i的位置,所以思路是重头扫描数组,遇到下标为i的数字如果不是i的话,(假设为m),那么我们就拿与下标m的数字交换。在交换过程中,如果有重复的数字发生,那么终止返回改数字。
该方法时间复杂度O(N),空间复杂度为O(1)。

代码

class Solution {

    /*************** 哈希表 时间O(N) 空间 O(N)**********************/
    public int findRepeatNumber1(int[] nums) {
        if(nums == null || nums.length == 0) return -1;
        Map<Integer,Integer> map= new HashMap<>();
        for(int i : nums){
            if(map.containsKey(i)) return i;
            map.put(i,1);
        }
        return -1;
    }

     /*************** 排序 时间O(NlogN) 空间 O(1)**********************/
    public int findRepeatNumber2(int[] nums) {
        if(nums == null || nums.length == 0) return -1;
        Arrays.sort(nums);
        for(int i = 0;i<nums.length-1;i++)
            if(nums[i] == nums[i+1]) return nums[i];
        return -1;
    }
     /*************** 鸠占鹊巢 时间O(N) 空间 O(1)**********************/
     public int findRepeatNumber(int[] nums) {
         if(nums == null || nums.length == 0) return -1;
         for(int i = 0;i < nums.length;i++){
             while(nums[i] != i){
                if(nums[nums[i]] == nums[i]) return nums[i]; //nums[i]作为索引
				//以i为索引的值和以nums[i]为索引处的值互换
                int tmp = nums[i];
                nums[i] = nums[tmp];
                nums[tmp] = tmp; 
             }
         }
         return -1;
     }
}

很明显,本题最理想的方法是方法三,原地置换。

你可能感兴趣的:(剑指offer)