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

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

一 找出数组中重复的数字

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

示例 1:

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

限制:

2 <= n <= 100000

题解

  • 解一:将数组排序后再遍历,需要时间复杂度O(nlogn),空间复杂度O(1)

  • 解二:使用哈希表,再遍历数组时判断哈希表中是否包含该数(O(1)),如果包含则找到重复数,如果不包含则把该数字加入哈希表。

时间复杂度和空间复杂度都是O(n)

  • 解三:因为输入的数字在0~n-1之间,所以可以在原数组上建立数字与下标的对应关系
    1. 遍历数组,如果nums[i]=i,则i++判断下一个
    2. 如果nums[i]不等于i,则记nums[i]为m,将数字m和在第m位上的数比较
      • 如果m=nums[m]则找到重复数
      • 否则将nums[m]与nums[i]交换
    3. 虽然有嵌套的循环,但每循环一次就会有一个数字回到原位或得出结果,所以时间复杂度是O(n)
    4. 空间复杂度O(1)
class Solution {
    public int findRepeatNumber(int[] nums) {
        int res=-1;
        for(int i=0;i<nums.length;i++){
            while(nums[i]!=i){
                int current=nums[i];
                if(nums[current]==current){
                    return current;
                }else {
                    nums[i]=nums[current];
                    nums[current]=current;
                }
            }
        }
        return res;
    }
}

二 不修改数组找出重复数

在一个长度为n + 1的数组里面的所有数字都在1 ~ n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应输出的重复数字应该是2或者3。

与题一类似,但要求不修改原数组,所以不能使用解一和解三,解二的话需要O(n)的空间复杂度,如果要求必须使用O(1)空间复杂度的算法呢?

  • 注意到题目要求:数组长度为n+1,而存的数字大小在1~n的范围内,所以说在这1~n的n个数中必定至少有一个数是重复的,所以可以考虑使用二分的思想。
  • 记1~n中间的数字为m,统计1~m中数字在数组中出现的次数,如果次数超过m,则说明重复数字大小在1~m的范围内,否则在m+1~n内

时间复杂度:二分查找的时间复杂度为O(logn),因为每一次二分完都需要O(n)的时间统计,所以总时间复杂度为O(nlogn).

空间复杂度:O(1)

算法不能找到所以重复的数字。

public static int findRepeatNumber(int[] nums) {
        int res=-1;
        int left=1;//从1开始
        int right=nums.length-1;
        while(left<=right){
            int mid=(right-left)/2+left;//中间数值为开始数值+左右数值差的一半
            int totalLeft=mid-left+1;
            int actualLeft=statisticsNumbers(nums,left,mid);
            if(left==right){
                if(actualLeft>1){//结束条件为左右指针重合,且统计的数字个数大于1,否则没有找到       																	 重复数
                    return left;
                }else {
                    break;
                }
            }
            if(actualLeft>totalLeft){
                right=mid;
            }else {
                left=mid+1;
            }
        }
        return res;

    }
    public static int statisticsNumbers(int[] nums,int start,int end){
        int count=0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]>=start && nums[i]<=end){
                count++;
            }
        }
        return count;
    }
posted @ 2021-04-07 17:33  五斗橱哪位啊v  阅读(65)  评论(0)    收藏  举报