JAVA 大厂笔试题 LeetCode41缺失的第一个正数

287. 寻找重复数

这个题说简单就简单在可以直接用set去重,但是空间复杂度是O(n);

代码:

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

但是题目要求是空间复杂度是O(1)

二分法:

对于 230724 二分查找的补充

   public static int findDuplicate(int[] nums) {
            int len = nums.length; // n +1 = len  n = len -1;
            int left = 0;
            int right = len - 1;
            //实则是二分查找[1...n] 这个区间
            // 这里不是左闭右开,只是循环可以继续的条件,为什么不需要继续搜索,
            // 原因就是如果最后left == right了,当前这个left或者right就一定是重复的那个元素
            while (left < right) {

                int mid = (left + right) / 2;
                // 统计大于mid的个数
                int count = 0;
                for (int x : nums) {
                    if (x <= mid) {
                        count++;
                    }
                }

                if (count > mid) {
                    //下一次搜索区间为[left ,mid]
                    right = mid;
                } else {
                    //下一次搜索区间为[mid+1,right]
                    left = mid + 1;
                }
            


            }
            return left;
        }

参考:

算法不好玩

8-9 「力扣」第 287 题:寻找重复数_哔哩哔哩_bilibili

关于左闭右闭,左闭右开的理解

   public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length-1;
       //这里 相等是因为 left==right的时候,还需要再进行一次循环,目的就是要不漏下数组里的数,全部比较到。
        while (left <= right){
            int mid = left + (right-left)/2;
            if (nums[mid] > target){
                right = mid-1;
            }else if (nums[mid] < target){
                left = mid+1;
            }else {
                return mid;
            }
        }
        //如果找不到,返回-1
        return -1;
    }

41. 缺失的第一个正数

不难,就是O(1) 的空间复杂度有点难。

哈希法:

时间复杂度O(n),空间复杂地O(n)

**巧妙点:**只需要循环查找到 len 就可以轻松查找到。

   public int firstMissingPositive(int[] nums) {
        int len = nums.length;

         Set<Integer> set = new HashSet<>() ;
         
         for(int x : nums){
             set.add(x);
         }  
         //这里巧妙在只需要搜索到len 就可以了。
         //[1,2,0] 这种情况 就可以保证 i= 3;
         //其他一般情况就基本都可以满足了
    
         for(int i = 1;i<=len;i++){
             if(!set.contains(i)){
                 
                return i;
                
             }
         }
         // [1,2,3] 这种情况 可以保证 i = 4;
         return len+1;
    }

原地哈希

空间复杂度O(1);

     public static int firstMissingPositive(int[] nums) {
            int len = nums.length;

            // 先原地哈希一下, 俗称找家 。家要满足  nums[i] = i+1;  也就是  下标为0 的放 数字 1
            for(int i = 0;i<len;i++){
                // nums[i] > 0 为了避免 nums[0-1] = nums[-1] 造成的索引越界
                // nums[i] <=len  [7,8,9,11,12] 这种情况没办法找到家,就不用动。
                // 我们要做的就是让能回家的回家,然后从1 开始看谁没回家,就是第一个正整数
                while(nums[i] > 0  && nums[i] <= len && nums[nums[i]-1] != nums[i]){

                    int temp = nums[i];
                    nums[i] = nums[temp-1];
                    nums[temp-1] = temp;


                }
            }
            // 看看谁没回到家
            for(int i =0;i<len;i++){
                if(nums[i]!=i+1){
                    return i+1;
                }
            }
            // 都回家了,那就是长度+1 个
            return len+1;
        }

原地哈希额外:

剑指 Offer 03. 数组中重复的数字

 public int findRepeatNumber(int[] nums) {
            
        int len = nums.length;
        for(int i =0;i<len;i++){
            while(nums[i]!=i){
                // 判断家是不是被人占领了。
                if(nums[nums[i]]==nums[i]){
                    return nums[i];
                }
                // 这个家没人,就交换,去入住
                int temp = nums[i];
                nums[i] = nums[temp];
                nums[temp]= temp;
            }

        }
     
     return -1;
    }

没人,就交换,去入住
int temp = nums[i];
nums[i] = nums[temp];
nums[temp]= temp;
}

    }
 
 return -1;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值