zoukankan      html  css  js  c++  java
  • 剑指Offer_#3_数组中重复的数字

    剑指Offer_#3_数组中重复的数字

    Contents

    题目

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

    示例 1:
    
    输入:
    [2, 3, 1, 0, 2, 5, 3]
    输出:2 或 3 
     
    
    限制:
    
    2 <= n <= 100000

    思路分析

    方法1:使用HashSet或HashMap

    HashSet和HashMap都是java当中collection框架里的一部分,他们的区别如下:

    HashMap和HashSet的区别
    HashMap和HashSet的区别

    我们可以把数组元素加入HashSet或者HashMap(作为键),利用了这两种数据结构数据的唯一性,当遇到重复的数组元素的时候,就直接返回这个元素即可。

    方法2:原地交换数组元素

    因为题目当中限制了数组元素的大小是在0~n-1范围内,如果每个数字只出现一次,刚好可以按顺序排列在长度为n的数组当中。
    那么可以将每个数组元素的数字(nums[i])放到下标nums[i]处,这样处理之后,所有位置满足nums[i] == i

    算法流程
    循环遍历整个数组,

    • 如果nums[i] == i,满足要求,所以不做处理
    • 如果nums[i] != i,进行判断
      • 如果nums[i] == nums[nums[i]],说明出现重复了,返回nums[i]
      • 如果nums[i] != nums[nums[i]],说明还没有放到应该在的位置,将nums[i]nums[nums[i]]交换位置。

    比起方法1,这个方法空间没有借助额外的变量,空间复杂度是O(1)

    方法3:排序后比较相邻元素

    先将数组排序,那么重复数字必然相邻。然后遍历排序后的数组,每次比较当前数字和后一个数字,如果相同,返回当前数字。

    解答

    解答1:使用HashSet

    class Solution {
        public int findRepeatNumber(int[] nums) {
            Set<Integer> set = new HashSet<Integer>();
            for(int i = 0; i <= nums.length - 1;i++){
                if(!set.contains(nums[i])) set.add(nums[i]);
                else return nums[i];
            }
            return -1;//表示遍历了nums,也没有找到重复的
        }
    }

    复杂度分析

    时间复杂度:O(n)
    空间复杂度:O(n)

    关于HashSet

    疑问:
    这里边直接就使用Set,这个Set属于什么类型呢?是一个接口?还是抽象类?还是具体类?
    解答:
    Set是接口,不可以实例化,但是Set类型的变量可以指向实现了Set接口的实体类的对象。
    例如:
    Set<int> set = new HashSet<int>(); (X)泛型的尖括号中间只可以传入包装类或者自定义的类,不可以传入类似于int这样的基本类型。
    正确写法:
    Set<Integer> set = new HashSet<Integer>();

    疑问:
    能否这么写?set.addAll(nums)
    解答:
    不可以,nums是普通数组,而非合集框架里边的类,所以不可以作为addAll这个方法的参数。

    解答2:原地交换数组元素

    class Solution {
        public int findRepeatNumber(int[] nums) {
            for(int i = 0;i <= nums.length-1;i++){
                if(nums[i] != i){//这里也可以写while,但是我觉得用while很奇怪,反正写if或者while都能过
                    if(nums[i] == nums[nums[i]]) return nums[i];
                    else{
                        int tmp = nums[i];
                        nums[i] = nums[tmp];
                        nums[tmp] = tmp;
                    }
                }
            }
            return -1;//没找到
        }
    }

    复杂度分析

    时间复杂度:O(n)
    空间复杂度:O(1)

    解答3:排序后比较相邻元素

    class Solution {
        public int findRepeatNumber(int[] nums) {
            Set<Integer> set= new HashSet<>();
            for(int num:nums){
                if(set.contains(num)) return num;
                set.add(num);
            }
            return -1;
        }
    }

    复杂度分析

    时间复杂度:O(nlogn),因为排序的复杂度是O(nlogn)
    空间复杂度:O(1)

  • 相关阅读:
    检测登录按钮 ,回车即登录
    [转]程序变量命名推荐规范
    [NET].NET Framework 3.5 SP1 真正的离线安装(转)
    Arthas使用教程[转载]
    Python中Hamcrest断言的使用
    C#中查询不支持中文的解决方法
    如何防止C#的小黑窗关闭
    AWS的EC2 micro instance真是慢啊
    一键分享文字图片到新浪微博,facebook,twitter 还有保存打印等 (使用 iOS6 自带的 social.framework)
    自己写的可以布置多个button在同一行的ActionSheet (iPhone)
  • 原文地址:https://www.cnblogs.com/Howfars/p/13405276.html
Copyright © 2011-2022 走看看