方案一:暴力求解
暴力求解的思路非常的直接:
- 遍历数组中的每个元素,然后在剩下的元素中寻找是否存在相同的元素
代码如下:
public int findRepeatNumber(int[] nums) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[i] == nums[j]) {
return nums[i];
}
}
}
return -1;
}
算法复杂度分析:
- 时间复杂度是 O(n^2)
- 空间复杂度是 O(1)
而本题对n做了一个限制
方案二:哈希查找
使用哈希表后的算法步骤是:
- 先初始化一个哈希表 (HashSet)
- 然后遍历每一个元素,分别对每一个元素做如下的处理:
代码如下:
public int findRepeatNumber(int[] nums) {
// 1. 初始化一个哈希表
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
// 2. 判断当前元素是否已经存在
if (set.contains(nums[i])) {
// 如果存在,则直接返回
return nums[i];
}
// 否则的话,将当前元素放入到哈希表中,方便后续的查找判重
set.add(nums[i]);
}
return -1;
}
算法复杂度分析:
- 时间复杂度是 O(n)
- 空间复杂度是 O(n)
方案三:数组代替哈希表
在题目中,有一个信息,我们需要注意下,那就是数组中每个元素的大小在 0 ~ n - 1 的范围内。利用这个信息,我们就可以使用数组代替上面方案二的哈希表,主要的思路是:
代码如下:
public int findRepeatNumber(int[] nums) {
// 1. 初始化一个数组
int[] bucket = new int[nums.length];
Arrays.fill(bucket, -1);
for (int i = 0; i < nums.length; i++) {
// 2. 判断当前元素是否已经存在
if (bucket[nums[i]] != -1) {
// 如果存在,则直接返回
return nums[i];
}
// 否则的话,将当前元素作为索引,当前元素的下标作为值,填入数组中,
// 方便后续的查找判重
bucket[nums[i]] = i;
}
return -1;
}
算法复杂度分析:
- 时间复杂度是 O(n)
- 空间复杂度是 O(n)
可以看出,时间复杂度和空间复杂度都是和用哈希表的解决方案是一样的。但是使用数组绝对会有性能的提高,主要表现在如下的两个方面: