題目
來源:力扣(LeetCode)
鏈接:有序數組的單一元素
分析
爲了分析方便,始終控制折半查找的子區間長度爲奇數。
設子區間爲[left,right]
mid=left+(right-left)/2
mid將子區間分爲兩個區間有如下幾種情況:
- 因爲重複出現的元素兩兩配對,若[left,mid-1]區間長度爲偶數
- 若
nums[mid] ==numd[mid-1]
,則說明單一元素下標一定在中,且這一子區間長度爲奇數。如子序列112334455中 ,單一元素在左半區間。 - 若
nums[mid]==nums[mid+1]
,則說明單一元素一定在右半區間中,爲保證右半區間長度爲奇數,則left=mid+2
如子序列112233455中 ,單一元素在右半區間。 - 若
nums[mid]!=nums[mid+1]&&nums[mid]!=nums[mid-1]
則返回nums[mid]
- 若
- 若[left,mid-1]區間長度爲奇數,
- 若
nums[mid]==nums[mid-1]
,則說明單一元素一定在右半區間中.爲保證右半區間長度爲奇數,則更新left=mid+1
。如子序列1122344中 ,單一元素在右半區間。 - 若
nums[mid]==nums[mid+1]
,則說明單一元素一定在左半區間中.爲保證左半區間長度爲奇數,則更新right=mid-1
。如子序列1123344中 ,單一元素在左半區間。 - 若
nums[mid]!=nums[mid+1]&&nums[mid]!=nums[mid-1]
則返回nums[mid]
- 若
代碼
int singleNonDuplicate(int* nums, int numsSize){
if(numsSize==1) return nums[0];
int left=0;
int right=numsSize-1;
int mid=0;
while(left<right){
mid=left+(right-left)/2;
if(mid==0||mid==numsSize-1||nums[mid]!=nums[mid+1]&&nums[mid]!=nums[mid-1])
return nums[mid];
int len=mid-left;
if((len)%2==0){
if(nums[mid]==nums[mid-1])
right=mid-2;//保證子區間nums[left]~nums[right]長度爲奇數
else
left=mid+2;
}else{
if(nums[mid]==nums[mid-1])
left=mid+1;
else
right=mid-1;
}
}
return nums[left];
}