給定一個包含 n + 1 個整數的數組 nums,其數字都在 1 到 n 之間(包括 1 和 n),可知至少存在一個重複的整數。假設只有一個重複的整數,找出這個重複的數。
示例 1:
輸入: [1,3,4,2,2]
輸出: 2
示例 2:
輸入: [3,1,3,4,2]
輸出: 3
說明:
不能更改原數組(假設數組是隻讀的)。
只能使用額外的 O(1) 的空間。
時間複雜度小於 O(n2) 。
數組中只有一個重複的數字,但它可能不止重複出現一次。
解法一:
抽屜原理,類似鏈表求環的雙指針思想
不斷交換,讓1-n個數都放在對應位置,出現重複那就是答案了
拿1 3 4 2 2舉例
第一次交換1應該在a[1],跟3交換
3 1 4 2 2
3應該在a[3]跟2交換
2 1 4 3 2
2應該在a[2]跟4交換
4 1 2 3 2
4應該在a[4]跟2交換
2 1 2 3 4
2應該在a[2]跟2交換…發現重複值了
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int slow = 0, fast = 0;
slow = nums[slow], fast = nums[nums[fast]];
while(slow != fast) {
slow = nums[slow];
fast = nums[nums[fast]];
}
int temp = 0;
while(slow != temp) {
temp = nums[temp];
slow = nums[slow];
}
return slow;
}
};
解法二:
二分思想,
藉助計數二分,每次循環計數小於mid的元素個數,以此來作爲依據判斷重複元素是在數組左側還是右側
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while(left < right) {
int mid = left + (right - left) / 2;
int count = 0;
for(auto a : nums) {
if(a <= mid) {
count++;
}
}
if(count <= mid) {
left = mid + 1;
} else {
right = mid;
}
}
return right;
}
};
解法三:
排序後直接判斷
class Solution {
public:
int findDuplicate(vector<int>& nums) {
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size(); i++) {
if(nums[i] == nums[i+1]) {
return nums[i];
}
}
return -1;
}
};
解法四:
藉助集合
class Solution {
public:
int findDuplicate(vector<int>& nums) {
set<int> st;
for(auto a : nums) {
if(st.count(a) > 0) {
return a;
}
st.insert(a);
}
return -1;
}
};