剑指Offer面试题3:数组中重复的数字(详解及C++代码)

题目描述

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

思路一

建立长度为n的哈希表,遍历数组,累计每个数出现的次数,当累计次数超过1时输出重复数字。时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)

思路二

进一步优化我们的思路,考虑有没有空间复杂度是 O ( 1 ) O(1) O(1)的算法?当然是有滴~

我们可以原地调整数组的顺序,使得数字 i 刚好在下标为 i 的位置(其实就是原地建立哈希表)。如果有重复数字,意味着有些位置存在多个数字。我们的目标是找到存在多个数字的位置。步骤如下:

  • 从头开始遍历数组中的每个数字,当扫描到第i个数字m时,比较m是否等于i。
    • 若是,则接着扫描下一个数字(m恰好在属于它的位置);
    • 若不是,则将第i个数字与第m个数字作比较
      • 若相等,就找到了一个重复的数字;
      • 若不相等,则将第i个数字和第m个数字交换位置(把m放到属于它的位置上)。

重复这个比较、交换的过程,直到我们发现一个重复的数字。
这时空间复杂度只需 O ( 1 ) O(1) O(1),时间复杂度依然为 O ( n ) O(n) O(n)

以下是C++代码(按照牛客网给的封装格式):

#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
	// Parameters:
    //        numbers:     an array of integers
    //        length:      the length of array numbers
    //        duplication: (Output) the duplicated number in the array number
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    bool duplicate(int numbers[], int length, int* duplication) {
        int m;
        for(int i=0;i<length;i++){
			if(numbers[i]>=length)	//检测异常输入
				return false;
            if(numbers[i]==i)
                i++;
            else{
                m=numbers[i];
                if(m==numbers[m]){
                    *duplication=numbers[i];
                    return true;
                }
                else{
                	//交换第i个数字和第m个数字的位置
                    numbers[i]=numbers[m];
                    numbers[m]=m;
                    i--;
                }
            }
            
        }
		return false;
    }
};
int main(){
	Solution s;
	int d;
	int a[]={2,1,3,1,4};
	bool f = s.duplicate(a,5,&d);
	cout<<f<<" "<<d<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值