剑指Offer-03 :数组中重复的数字

找出数组中重复的数字。

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

示例 1:

输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3

限制:

2 <= n <= 100000

链接:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof

解法1:
思路:emmmmm…数组中找重复的数字??那当然是排序了!!排序后重复的数字不就挨着了!嗯!就这样!


  // 先排序 在遍历数组
   
   public int findRepeatNum(int[] nums) {
    
    
       
        if (nums==null || nums.length==0)
            return -1;
        Arrays.sort(nums);
        int j=0;
        for (int i = 0; i < nums.length-1; i++) {
    
    
            j=i+1;
            if (nums[i]==nums[j]){
    
    
                return nums[i];
            }
        }
        return -1;
       }

其实也没有那么难啦:)哎!再回头一看!时间复杂度O(nlogn) 空间复杂度O(1),看着好像还不错不过还有没有其他的解法呢?

解法2:
思路:解法1的时间复杂度可不可以在优化下呢?哦!我想起来了!数据结构!!!可以用HashSet! 直接遍历数组,HashSet中不存在的直接加进去,如果HashSet中已经存在的话就找到一个重复数字!

public int findRepeatNum(int[] nums) {
    
    
	 if (nums==null || nums.length==0)
            return -1;
        Set<Integer> set=new HashSet<Integer>();
        for (int i = 0; i < nums.length; i++) {
    
    
			//如果HashSet中已经有这个数字了 就找到一个重复数字
            if (set.contains(nums[i])){
    
    
                return nums[i];
            }
            set.add(nums[i]);
        }
		
        return -1;
}

这回好了!时间复杂度O(n)了,不过空间复杂度从O(1)变成O(n)了!典型的空间换时间!有没有更好的解法呢?我们看再看看有没有空间复杂度O(1)的算法呢?

扫描二维码关注公众号,回复: 13134965 查看本文章

在坚持坚持马上就拿到最优的算法了!!!不战斗就无法生存!

解法3:
思路
:我们注意到数组中的数字都在0-n-1的范围内,如果数组中没有重复的数字,那么是不是重排后的数字i应该出现在下表为i的位置?由于数组中有重复的数字有些位置可能存在多个数字,同时也有些位置可能没有数字!接下来我们对数组进行重排,怎么重排呢?首先呢,我们遍历数组,当遍历到下标为i的数字时,首先比较这个数字(用m表示)是不是等于i,true的话继续扫描下一个数字,false的话呢,则拿他和第m个数字比较。如果他和第m个数字相同,则找到一个重复数字,如果不相等呢?就把m放到它自己的位置(交换),接下来重复这个过程!直到我们发现一个重复的数字

举个栗子:
[2,3,1,0,2,5,3]
开始扫描数组,第一个数字是2与它的下标不相等,于是把他和nums[2]的数字1交换数组变成[1,3,2,0,2,5,3] ,发现第一个数字还是与它的下表不相等,重复刚才的过程!数组变成[3,1,2,0,2,5,3] 。害!还是不等,继续!数组变成[0,1,2,3,2,5,3] !终于相等了!!接下来继续扫描数组,他们的值和下表都相等。接下来到下表为4的数字了,发现他不等于它的下标,在比较一下他和下标为2的数字!
相等!找到一个重复数字!也就是说一个数字在两个位置出现了两次!
接下来看代码

  public int findRepeatNum(int[] nums) {
    
    
  
        if (nums==null || nums.length==0){
    
    
            return -1;
        }
        for (int i = 0; i < nums.length; i++) {
    
    
            if (nums[i]<0)
                return -1;
        }
        //重排数组
        for (int i = 0; i < nums.length; i++) {
    
    
        //如果下表和值不相等的话 重复这个过程!
            while (nums[i]!=i){
    
    
            	//进行比较
            	//如果同一个数字出现了两次
                if (nums[i]==nums[nums[i]]){
    
    
                    return nums[i];
                }else{
    
    //交换         
                int temp=nums[i];
                nums[i]=nums[temp];
                nums[temp]=temp;
                }
				
            }
        }
        return -1;
  }

这回在看看!尽管有一个双重循环,但每个数字只要交换两次就能找到属于它自己的位置!因为时间复杂度为O(n) 空间复杂度O(1)!终于找到最优啦!!!!

如果觉得对你有帮助的话,就点个赞叭,嘿嘿。

提醒:
大家在解题的时候一定要想到测试用例!
这道题的测试用例:
1.有一个或多个重复数字!
2.没有重复的数字!
3.无效输入!(空指针,或者数组中包含1-n-1)之外的数字!

猜你喜欢

转载自blog.csdn.net/daniu_weilai/article/details/115277181
今日推荐