力扣287(java&python)-寻找重复数(中等)

题目:

给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。

假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。

你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。

 

示例 1:

输入:nums = [1,3,4,2,2]
输出:2
示例 2:

输入:nums = [3,1,3,4,2]
输出:3
 

提示:

  • 1 <= n <= 105
  • nums.length == n + 1
  • 1 <= nums[i] <= n
  • nums 中 只有一个整数 出现 两次或多次 ,其余整数均只出现 一次

进阶:

  • 如何证明 nums 中至少存在一个重复的数字?
  • 你可以设计一个线性级时间复杂度 O(n) 的解决方案吗?

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/find-the-duplicate-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

一、暴力【HashSet】

一看到条件说只有一个重复数,就想到了hashset无重复数这个特点,遍历整个数组,如果hashset已存在该数说明遇到重复数,则直接返回当前数。(但是这种方法不满足题目要求的时间复杂度)

java代码:

 1 class Solution {
 2     public int findDuplicate(int[] nums) {
 3         HashSet<Integer> set =  new HashSet<>();
 4         for (Integer num : nums){
 5             if (set.contains(num)){
 6                 return num;
 7             }else {
 8                 set.add(num);
 9             }
10         }
11         return -1;
12     }
13 }

二、【二分查找】

使用二分查找主要需要弄清楚搜索区间,每一次猜一个数,然后 遍历整个输入数组,进而缩小搜索区间,最后确定重复的是哪个数。

  • 题目中给出数组的长度是:n+1,但是数字是1~n,必然有一个重复数字,应该在数字1~n中搜索,代码中设数组的长度为n,故搜索范围[1, n-1],这里[1,n-1]并不是数组的下标索引,而是数字1~n-1,即左右指针为:left = 1, right = n-1;
  • 在计算出mid以后,统计已知数组中小于等于mid的数的个数count,如果 count 大于 mid,说明重复元素就在区间 [left..mid] 里,否则,由于只存在一个重复元素,于是只能在区间 [mid + 1..right] 里找到;
  • 循环结束的条件是:left == right,这时left 或者right就是我们要找的重复整数。

举例:

[1,2,3,3,4,5,6,7],mid = 3, 小于等于mid的个数count = 4,但是正常小于等于mid的个数应该只有3个(count > mid),说明存在一个重复元素在小于等于mid的范围中,继续在[1,3]去找 (即让right = mid)。

[1,2,3,4,5,6,7,8,8,9],mid=5,小于等于mid的个数count = 5,符合要求(count = 5),题目也说了只存在一个重复元素,mid前面不存在重复元素,重复元素只能存在mid后面了,继续在[5,9]去找(即让left = mid)

 java代码(left < right):

 1 class Solution {
 2     public int findDuplicate(int[] nums) {
 3        int n = nums.length;
 4        int left = 0, right = n - 1;
 5        while (left < right){
 6            int mid = left + (right - left) / 2;
 7            int count = 0;
 8            for (int num : nums){
 9                if (num <= mid){
10                    count++;
11                }
12            }
13            if (count > mid){
14                right = mid;
15            }else{
16                left = mid + 1;
17            }
18        }
19        return left;
20     }
21 }

 python3代码(left <= right):

 1 class Solution:
 2     def findDuplicate(self, nums: List[int]) -> int:
 3         left, right = 1, len(nums) - 1
 4         while left <= right:
 5             mid = left + (right - left) // 2
 6             count = 0
 7             for num in nums:
 8                 if num < mid:
 9                     count += 1
10             if count >= mid:
11                 right = mid - 1
12             else:
13                 left = mid + 1
14         return right

posted on 2022-11-30 19:37  我不想一直当菜鸟  阅读(49)  评论(0编辑  收藏  举报