• 287.寻找重复的数


    image-20200527122935680

    思路

    • 本题设置的条件很特殊 ,解法反常规,用时间换空间
    • 我也只能想到哈希解法 该解法还不符合要求2
    • 参考各种题解 收集以下解法(不局限于题设要求)

    哈希

    /**
     * 使用HashMap   2ms  但不能满足 要求2
     */
    public static int findDuplicate(int[] nums) {
        int ans=0;
        Map<Integer,Integer> map=new HashMap<>();
        for (int num : nums) {
            if (map.containsKey(num)) {
                return num;
            } else {
                map.put(num, 1);
            }
        }
        return ans
    

    更改原数组

    /**
     * 2ms  但不满足要求 1
     *  
     * 非重复的数字只会改一次正数变成负数,之后就不会访问了,
     * 重复的数字会在第二次索引看到之前变为负数的值
     */
    public int findDuplicate3(int[] nums){
        for(int i=0;i<nums.length;i++){
            if(nums[Math.abs(nums[i])]<0) return Math.abs(nums[i]);
            nums[Math.abs(nums[i])]=-nums[Math.abs(nums[i])];
        }
        return -1;
    }
    

    二分法(抽屉原理)

    原文思路参考:

    liweiwei1419:使用二分法查找一个有范围的整数(结合抽屉原理)

    /*
     * 2ms 
     * 
     */
    public int findDuplicate(int[] nums) {
        int len = nums.length;
        int left = 1;
        int right = len - 1;
        while (left < right) {
            // 在 Java 里可以这么用,当 left + right 溢出的时候,无符号右移保证结果依然正确
            int mid = (left + right + 1) >>> 1;
    
            int cnt = 0;
            for (int num : nums) {
                if (num < mid) {
                    cnt += 1;
                }
            }
    
            // 根据抽屉原理,严格小于 4 的数的个数如果大于等于 4 个,
            // 此时重复元素一定出现在 [1, 3] 区间里
    
            if (cnt >= mid) {
                // 重复的元素一定出现在 [left, mid - 1] 区间里
                right = mid - 1;
            } else {
                // if 分析正确了以后,else 搜索的区间就是 if 的反面
                // [mid, right]
                // 注意:此时需要调整中位数的取法为上取整
                left = mid;
            }
        }
        return left;
    }
    
    • 时间复杂度:O(N log N),二分法的时间复杂度为 O(logN),在二分法的内部,执 行了一次 for 循环,时间复杂度为 O(N),故时间复杂度为 O(N logN)。
    • 空间复杂度:O(1)

    快慢指针

    题解参考

    官方题解

    jsl:前端灵魂画师图解快慢指针

    /*
     *0ms 
     *时间复杂度O(n)
     *空间复杂度O(1)
     */
    class Solution {
        public int findDuplicate(int[] nums) {
            int slow = 0, fast = 0;
            do {
                slow = nums[slow];
                fast = nums[nums[fast]];
            } while (slow != fast);
            slow = 0;
            while (slow != fast) {
                slow = nums[slow];
                fast = nums[fast];
            }
            return slow;
        }
    }
    

    题解参考

    明知山有虎?:287.寻找重复数

    class Solution {
        public int findDuplicate(int[] nums) {
    
            if(nums.length <= 2){
                return nums[0];
            }
            //初始化i,j不应该为0.应该是指向第一个index与nums[index]不相等的位置.
            int i = 0,j = 0;
            for(int index = 0; index<nums.length; index++){
                if(index != nums[index]){
                    i = index;
                    j = index;
                    break;
                }
            }
            while(true){
                i = nums[i];
                j = nums[nums[j]];
                if(i == j) break;
            }
            i = 0;
            while(true){
                i = nums[i];
                j = nums[j];
                if(i == j) break;
            }
            return i;
        }
    }
    

    小结

    • 第一次了解抽屉原理,惊叹二分法的新用法,当然题解还需好好理解。
  • 相关阅读:
    java读取properties文件的几种方法
    mysql中的一些操作
    Threalocal的使用及其原理
    ResourceBundle和properties 读取配置文件区别
    (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
    mysql中的unique
    JSP标签 <meta> 的作用
    面向对象、匿名内部类
    Katalon Studio 安装 配置 简单使用
    Sonar 规则
  • 原文地址:https://www.cnblogs.com/yh-simon/p/12994881.html
Copyright © 2020-2023  润新知