剑指Offer——面试题03. 数组中重复的数字

面试题03. 数组中重复的数字

题目描述

找出数组中重复的数字。

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

示例 1

输入:

[2, 3, 1, 0, 2, 5, 3]

输出:

2 或 3 

限制:

2 <= n <= 100000

解题思路

1. 数组排序(纯暴力),时间复杂度O(nlogn)

2. 哈希,时间复杂度O(n),空间复杂度O(n)(哈希表辅助)

3. 注意到数组中的数字是在0到n-1之间的,那么可以想一下,如果这个数组没有重复数字,那么排好序的数组中,i会出现在下标为i的位置。所以说,如果下标为i的位置的数字经过排序之后不是i,就说明出现了重复数字。从头到尾依次扫描数组中的每个数字,当扫描到下标为i的数字时,首先比较这个数字m是不是等于i。如果相等则扫描下一个数字,否则将m和下标为m的数字进行比较,如果两者相等则找到了重复数字,如果不等,则把m和下标为m的数字交换,重复比较直到找到重复的数字。对于每个数字,最多只需要交换两次,因此总时间复杂度是O(n)。而且所有步骤都在输入的数组上进行,所以不需要额外分配内存,空间复杂度为O(1)。这种方法也称作数组的“原地置换”。

C++版本

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        int length = nums.size();
        if(length <= 0)
            return false;
        //这里书本写的很好,对异常进行了判断
        for(int i = 0; i < length; i++)
        {
            if(nums[i] < 0 || nums[i] >= length)
                return false;
        }
        //接下来开始循环比较
        for(int i = 0; i < length; i++)
        {
            //对于数组中的一个数来讲,经过最多两次交换一定可以交换到它对应的位置,因此不会是死循环
            while(nums[i] != i)
            {
                //将m,也就是nums[i],与nums[m],也就是nums[nums[i]]做比较,如果相同则找到了重复数字
                if(nums[i] == nums[nums[i]])
                {
                    return nums[i];
                }
                //否则,交换两者的位置
                int t = nums[i];
                nums[i] = nums[t];
                nums[t] = t;
            }
        }
        return false;
    }
};

Java版本

class Solution {
    public int findRepeatNumber(int[] nums) {
        if(nums.length <= 0)
            return -1;
        //同样还是需要判断异常情况
        for(int i = 0; i < nums.length; i++)
        {
            if(nums[i] >= nums.length || nums[i] < 0)
                return -1;
        }
        //原地置换
        for(int i = 0; i < nums.length; i++)
        {
            while(i != nums[i])
            {
                if(nums[i] == nums[nums[i]])
                {
                    return nums[i];
                }
                int t = nums[i];
                nums[i] = nums[t];
                nums[t] = t;
            }
        }
        return -1;
    }
}

 

本题难度:✭✭✭

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值