【剑指offer】面试题3-数组中的重复数字

题目

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

1.思路

思路1
(1)新建一个数组index,遍历原数组numbers,用numbers[i]作为下标访问数组index,并将index[ numbers[i] ] ++;
(2)遍历数组index,如果遇到index[i] >= 2,说明有重复数字,返回true,否则遍历结束之后返回false即可。
思路2
新建一个set,遍历数组并将其元素依次存入set,借助其计数函数count()来判断数组中是否有元素重复,因为set是无重复值的一种数据结构,所以只要当前访问到的原数组中的元素值在set中计数不为0,说明是重复元素,直接将其返回即可。
思路3
新建一个map<key,value>,其中,以原数组中的函数值作为key,布尔值bool作为value,即map初始化为map<int,bool>,map的特点是key值无重复,初次遍历到的数组元素,将其对应在map中的value值设置为true,当在数组中再次遍历到相同元素时,便会发现其value值已经为true,直接返回该重复元素即可。该思路与思路2很相似。
思路4
排序后遍历,存在相等的相邻元素,即为重复。
思路5
这是一个不成熟的思路,运行时间不符合标准,但是很容易被想到,双重循环遍历查找重复元素。
思路6

引用 剑指offer 作者的思路
在一个长度为n的数组nums里的所有数字都在0 ~ n-1的范围内。即数组元素的索引和值是一对多的关系。因此,可遍历数组并通过交换操作,使元素的索引与值一一对应(即nums[i]=i)。
遍历过程中,第一次遇到数字x时,将其交换至索引x处;而当第二次遇到数字x时,一定有nums[x]=x,此时即可得到一组重复数字。
算法流程:
遍历数组 nums ,设索引初始值为 i = 0 :
若nums[i] = i:说明此数字已在对应索引位置,无需交换,continue;
若nums[nums[i]] = nums[i]:代表索引nums[i]处和索引i处的元素值都为nums[i],即找到一组重复值,返回nums[i];
否则:交换索引为i和nums[i]的元素值,将此数字交换至对应索引位置。
若遍历完毕尚未返回,则返回 -1。
复杂度分析:
时间复杂度O(N):遍历数组使用O(N),每轮遍历的判断和交换操作使用O(1) 。
空间复杂度O(1):使用常数复杂度的额外空间。

2.代码

思路1 Java实现 借助数组

public class Solution {
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        int [] index = new int[length+1];	//index的容量多设些
        int i = 0;
        //遍历numbers数组并更新index数组
        for(i = 0; i < length; i++){
            index[numbers[i]] ++;
        }
        //判断有没有重复数字
        for(i = 0; i < length; i++){
            if(index[i] >= 2){
                duplication[0] = i;
                return true;
            }
        }
        return false;
    }
}	//O(n)

思路2 c++实现 借助set

class Solution
{
public:
    int findRepeatNumber(vector<int>& nums)
    {

        set <int> temp;
        for (int i = 0; i < nums.size(); i++){
            cout<<nums[i]<<endl;
            if (temp.count(nums[i]) != 0){
                return nums[i];
            }
            temp.insert(nums[i]);
        }
        return -1;
    }
};

思路3 c++实现 借助map

class Solution
{
public:
    int findRepeatNumber(vector<int>& nums)
    {
        map<int, bool> temp;
    for (std::vector<int>::iterator it = nums.begin(); it != nums.end(); ++it)
        {
            if (temp[*it])
            {
                return *it;
            }
            temp[*it] = true;
        }
        return -1;
    }
};

思路4 c++实现 排序后遍历

class Solution
{
public:
    int findRepeatNumber(vector<int>& nums)
    {
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size() - 1; i ++){
            if (nums[i] == nums[i+1]){
                return nums[i];
            }
        }
        return -1;
    }
};

思路5 c++实现 双重遍历 时间复杂度不符合要求

class Solution
{
public:
    int findRepeatNumber(vector<int>& nums)
    {
        std::vector<int>::iterator it, itr;
        for (it = nums.begin(); it != nums.end(); ++it){
            for (itr = it+1; itr != nums.end(); ++itr){
                //printf("%d, %d\n", *it, *itr);
                if (*it == *itr){
                    return *it;
                }
            }
        }
        return -1;
    }
};

思路6 c++实现 剑指offer作者的巧妙思路

class Solution
{
public:
    int findRepeatNumber(vector<int>& nums)
    {
        int i = 0;
        while(i < nums.size())
        {
            if(nums[i] == i)
            {
                i++;
                continue;
            }
            if(nums[nums[i]] == nums[i])
            {
                return nums[i];
            }
            int temp = nums[i];
            nums[i] = nums[nums[i]];
            nums[temp] = temp; // 注意这里不能写成nums[nums[i]]!因为nums[i]的值已经改变了!
        }
        return -1;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值