算法学习100天——3 二分查找2
题目地址(540. 有序数组中的单一元素)
https://leetcode-cn.com/problems/single-element-in-a-sorted-array/
题目描述
给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。
你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度。
示例 1:
输入: nums = [1,1,2,3,3,4,4,8,8]
输出: 2
示例 2:
输入: nums = [3,3,7,7,10,11,11]
输出: 10
提示:
1 <= nums.length <= 105
0 <= nums[i] <= 105
代码
- 语言支持:Java
class Solution {
public int singleNonDuplicate(int[] nums) {
// 二分查找 时间复杂度是logN;
// 但是我不知道target, 这是我不理解的地方
// 考虑直接比较mid左右两边,如果没有与mid相等的,那就是mid,但是最坏的情况就是O(N)了
// 看了评论提示,关键点:数组元素是2*M + 1, 长度永远为奇数,可以二分中点来判断,
// 两种思考角度如下
// 4种情况(先考虑目标点位置):
// 1. 目标点在左边,中点与左邻点相等,则执行right = mid;
// 2. 目标点在左边,中点与右邻点相等,则执行right = mid - 1;(或者+1)
// 3. 目标点在中间或者右边,中点与左邻点相等,则执行left = mid + 1;(或者-1)
// 4. 目标点在中间或者右边,中点与右邻点相等,则执行left = mid;
// 5种情况(先判断中点值与左右邻点值的关系):
// 1. 中点与左邻点相等,目标点在左边,则执行right = mid;
// 2. 中点与左邻点相等,目标点在右边,则执行left = mid + 1;(或者-1)
// 3. 中点与右邻点相等,目标点在左边,则执行right = mid - 1;(或者+1)
// 4. 中点与右邻点相等,目标点在右边,则执行left = mid;
// 5. 中点与左右邻点都不相等,目标点就是中点,直接return nums[mid];
// 数组长度为1的情况
if(nums.length == 1){
return nums[0];
}
int left = 0;
int right = nums.length - 1;
while(left < right){
// 找到中点
int mid = left + ((right - left) >> 1);
// 判断中点与两边的大小
if(nums[mid] == nums[mid - 1]){
if(mid % 2 == 0) {
right = mid;
}else {
left = mid + 1;
}
}else if(nums[mid] == nums[mid + 1]){
if(mid % 2 == 0) {
left = mid;
}else {
right = mid - 1;
}
}else{
// 两边都不相等,直接返回它
return nums[mid];
}
}
return nums[left];
}
}
结果
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:47 MB, 在所有 Java 提交中击败了54.85%