找出數組中重複的數字。
在一個長度爲 n 的數組 nums 裏的所有數字都在 0~n-1 的範圍內。數組中某些數字是重複的,但不知道有幾個數字重複了,也不知道每個數字重複了幾次。請找出數組中任意一個重複的數字。
示例 1:
輸入:
[2, 3, 1, 0, 2, 5, 3]
輸出:2 或 3
解法一:暴力枚舉
class Solution {
public int findRepeatNumber(int[] nums) {
int n = nums.length;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] == nums[j])
return nums[i];
}
}
return -1;
}
}
時間複雜度:O(N^2)
空間複雜度:O(1)
解法二: 排序
class Solution {
public int findRepeatNumber(int[] nums) {
int n = nums.length;
//對數組排序,若相鄰兩個元素相等,則返回
Arrays.sort(nums);
for (int i = 1; i < n; i++) {
if (nums[i] == nums[i-1])
return nums[i];
}
return -1;
}
}
時間複雜度:O(NlogN)
空間複雜度:O(1)
解法三:哈希表
使用哈希表,採取空間換時間的思想!使用 HashSet 來進行處理,因爲 HashSet 本身不允許出現重複元素,所以當添加元素失敗或已經包含該數字時,則表示出現了重複元素,將其返回即可。
class Solution {
public int findRepeatNumber(int[] nums) {
Set<Integer> set = new HashSet<Integer>();
int repeat = -1;
for (int num : nums) {
if (!set.add(num)) {
repeat = num;
break;
}
}
return repeat;
}
}
時間複雜度:O(n)。
遍歷數組一遍。使用哈希集合(HashSet),添加元素的時間複雜度爲 O(1),故總的時間複雜度是 O(n)。
空間複雜度:O(n)。不重複的每個元素都可能存入集合,因此佔用 O(n) 額外空間。
解法四:原地置換
- 從題目描述中我們可以看出,因爲所有數字都在 0 ~ n-1 的範圍內,其實完全可以省掉額外的空間開闢,將每個位置的數交換映射到其對應的數組下標下面,當出現新的元素與其對應的下標中的數字相等時,即爲重複數字
- 這本質還是哈希的思想,前者思路是使用庫函數申請額外空間,後者思路則是數組本身做哈希表,達到了節省空間的目的
- 此處會用到 while 循環,原因是保證交換過來的新元素位置也要正確
class Solution {
public int findRepeatNumber(int[] nums) {
int n = nums.length;
for (int i = 0; i < n; i++) {
while (nums[i] != i) {
if (nums[i] == nums[nums[i]])
return nums[i];
int temp = nums[i];
nums[i] = nums[temp];
nums[temp] = temp;
}
}
return -1;
}
}