給定一個包含 n + 1 個整數的數組 nums,其數字都在 1 到 n 之間(包括 1 和 n),可知至少存在一個重複的整數。假設只有一個重複的整數,找出這個重複的數。
不能更改原數組(假設數組是隻讀的)。
只能使用額外的 O(1) 的空間。
時間複雜度小於 O(n²) 。
數組中只有一個重複的數字,但它可能不止重複出現一次。
開始思考時時準備使用字典來,健對值簡單粗暴,然後發現不符合題目說的空間複雜度,於是就考慮別的方法。從leetcode上看到二分法可以解決,
利用n+1個數,每個數都在1到n之間。
重複的數也是在1到n之間。
對[1,n]二分,確定重複的數在區間的那邊。
例如:[4,3,1,2,1]
n=4
mid=(1+4)/2=2
小於等於mid=2的數的個數爲3,[1,2,1]。
明確如果沒有重複,<=2的數的個數應該爲2.
這說明重複的數在[1,2]這個區間中。
mid=(1+2)/2=1。
<=mid=1的數的個數爲2.
如果沒有重複,<=1的數的個數應該爲1.
說明1重複了。
int n = nums.Length;
int l = 1, r = n - 1, ans = -1;
while (l <= r)
{
int mid = (l + r) >> 1;//右移運算符,二分數組。
int cnt = 0;
for (int i = 0; i < n; ++i)
{
if (nums[i] <= mid)
{
cnt++;//比mid小的個數
}
}
if (cnt <= mid)//如果小於等於mid說明重複數字不在範圍內,擴大繼續查找
{
l = mid + 1;
}
else//重複數字在範圍內縮小範圍直到查找到重複數字
{
r = mid - 1;
ans = mid;
}
}
return ans;