《剑指offer》面试题 3:数组中重复的数字(C++实现)

题目

面试题3(一):找出数组中重复的数字

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

面试题3(二):不修改数组找出重复的数字

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

代码

#pragma once
#include <iostream>
using namespace std;

// 题目一:找出数组中重复的数字 0~n-1 长度n
/**
 * 一维数组在内存中连续存储,可以根据下标定位对应的元素
 */
bool duplicate(int* number, int length, int* duplication)	// duplication为重复值
{
	// 边界条件 无效输入检查
	if (number == nullptr || length <= 0)
		return false;

	for (int i = 0; i < length; ++i)
	{
		if (number[i]<0 || number[i]>length - 1)
			return false;
	}

	for (int i = 0; i < length; ++i)
	{
		while (number[i] != i)
		{
			if (number[i] == number[number[i]])
			{
				*duplication = number[i];
				return true;
			}
			// 不相等则交换
			int tmp = number[i];
			number[i] = number[tmp];
			number[tmp] = tmp;
		}
	}

	return false;
}


// 题目二:不修改数组找出重复的数字 1~n	长度n+1(要多1)
/**
 * 一维数组在内存中连续存储,可以根据下标定位对应的元素
 * 查找任意一个重复数字,可利用二分查找算法
 * 若是全部重复数字,可利用辅助数组
 */
int getDuplication(int* number, int length)
{
	if (number == nullptr || length <= 0)
		return -1;

	for (int i = 0; i < length; ++i)
	{
		if (number[i]<1 || number[i]>length - 1)	// 1~length-1
			return -1;
	}

	// 二分查找
	int start = 1;
	int end = length - 1;
	while (end > start)
	{
		int mid = (start + end) / 2;
		// 统计在整个数组里该区间的数字的数目
		int count = countRange(number, length, start, mid);

		if (end == start)
		{
			if (count > 1)
				return start;
			else
				break;
		}

		if (count > mid - start + 1)
			end = mid;
		else
			start = mid + 1;
	}

	return -1;
}

// 统计在整个数组里该区间的数字的数目
int countRange(int* number, int length, int start, int end)
{
	int count = 0;
	for (int i = 0; i < length; ++i)
		if (number[i] >= start && number[i] <= end)
			++count;
	return count;
}

总结

(题目一)将下标为 i 的数字 m 和下标为 m 的数字相比较,不相等则交换,直到相等为止。时间复杂度 O(n)。

(题目二)二分法划分数字区间 1~n 为 1~m(中间值)和 m+1~n,计算区间内数字在数组中出现次数,若大于该区间差值则应在该区间继续二分查找。时间复杂度 O(nlogn)。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值