题目介绍:
- 在一个长度为n的数组里,所有的数字都在0到n~1的范围内!
- 数组中某些元素是重复的,有些是不重复的。
- 请找出数组中任意一个重复的数字。
题目分析:
一些简要的思路:
- 先把数组排序,排序好的数组要找出重复的数字很是容易,只需要从头到尾扫面一遍就可以了。排序的时间复杂度是O(nlogn)。
- 用哈希表表示:从头到尾扫描数组的每个数字,每扫描一个数字,就可以用O(1)的时间判断哈希表里是否包含了该数字。如果哈希表里还没有这个数字,就把它加入哈希表,如果哈希表里面已经存在该数字,就找到了一个重复数字。这个算法的时间复杂度是O(n),但是他提高时间效率的代价是以一个大小为O(n)的哈希表为代价的。
对题目的分析:
观察数组,发现数组的数字都在0-n-1的范围内。即如果这个数组中没有重复的数字,那么排序后元素 i 将出现在下标为 i 的位置。
例如:数组 [2,1,0],长度为3,即数组中的元素都要在0-2之间,符合要求,那么排序后,数组变为 [0,1,2],和数组元素的下标一致。
由于数组中有重复的数字,有些位置可能存在多个数字,同时有些位置可能没有数字。
详细思路:
- 从头到尾扫描这个数组中每一个数字。当扫描到下标为 i 的数字时,首先比较这个数字(m)是不是等于 i 。
- 如果是,说明这个数字是在排好序后的位置,则继续扫描下一个数字;
- 如果不是,则再拿数字(m)和下标为 m 对应的数字比较。
- 如果数字(m)和第m个数字相等,就找到一个重复的数字(因为该数字在下标i和m的位置都出现了。);
- 如果数字(m)和第m个数字不相等,就把这两个数字交换,即把数字(m)放到下标为m的位置上。
- 接下来继续重复比较、交换这样的步骤,直到我们发现一个重复的数字。
代码实现与验证(Python):
class Solution:
def duplicate(self,array):
if array == None or len(array) <= 0: # 数组为空,直接False
return False
for i in range(len(array)):
if array[i] < 0 or array[i] >= len(array): # 数组中的元素都应在0-n-1之间,否则False
return False
for i in range(len(array)): # 遍历
while array[i] != i: # 若下标和元素值不等,则一直循环下去
if array[array[i]] == array[i]: # 若下标为i的元素 array[i] 和下标为 array[i] 的元素相等,则重复,返回array[i]
return array[i]
else: # 否则,交换
array[array[i]], array[i] = array[i], array[array[i]]
return False
if __name__=='__main__':
# 验证
# 数组中不含重复的数字
test_1 = [3,1,2,0]
# 长度为 n 的数组里包含一个或多个重复的数字
test_2 = [2, 3, 1, 0, 2, 5, 3]
# 数组为空
test_3 = None
# 数组中元素值超出了0-n-1
test_4 = [2, 6, 1, 0]
solution = Solution()
print("test_1:", solution.duplicate(test_1))
print("test_2:", solution.duplicate(test_2))
print("test_3:", solution.duplicate(test_3))
print("test_4:", solution.duplicate(test_4))
验证结果:
test_1: False
test_2: 2
test_3: False
test_4: False
复杂度分析:
时间复杂度:
上述代码中,有两个循环,但是每一个数字最多交换两次就可以找到属于它自己的位置,因此总的时间复杂度的 O(n)。
空间复杂度:
上述代码的所有操作都是在原数组上进行的,不需要额外分配内存,因此空间复杂度是 O(1)。
C++实现
#include <iostream>
using namespace std;
/*****************************************/
// 参数:
// numbers: 一个整数数组
// length: 数组的长度
// 返回值:
// 数组中的一个重复的数字
/*****************************************/
class Solution {
public:
bool duplicate(int numbers[], int length)
{
if (numbers == nullptr || length <= 0)
{
cout << "数组为空!" << endl;
return false;
}
for (int i = 0; i < length; i++)
{
if (numbers[i]<0 || numbers[i]>length)
{
cout << "数组中元素超出范围!" << endl;
return false;
}
}
for (int i = 0; i < length; i++)
{
while (numbers[i] != i)
{
if (numbers[i] == numbers[numbers[i]])
{
cout << numbers[i] <<endl;
return true;
}
else
{
int temp = numbers[i];
numbers[i] = numbers[temp];
numbers[temp] = temp;
}
}
}
return false;
}
};
Solution solution;
int main()
{
int numbers[7] = { 2,3,1,0,2,5,3};
//int *numbers = nullptr;
int length = 7;
solution.duplicate(numbers, length);
return 0;
}
输出:2