Leecode 540 有序数组中的单一元素
算法描述:
540.有序数组中的单一元素给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。
你设计的解决方案必须满足 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
题目链接:点我跳转题目
算法思路:
思路一:
遍历,从头开始遍历数组,步长设置为2,逐个判断当前元素和后一元素是否相同,若不同,则证明前一元素为单一元素,相同则继续向后遍历,一直遍历到数组最后。
思路二:
首先是不含有单位元素的数组及其对应的下标,第一个重复元素的下标都为偶数,第二个重复元素的下标都为奇数
1 1 3 3 4 4 8 8
0 1 2 3 4 5 6 7
然后是含有单位元素的数组及其对应的下标记,在单位数左边,依然遵循刚才的规则,在单位数右边,由于加入了单位数
第一个重复元素的下标向后加了一位变为了奇数,第二个重复元素的下标变为了偶数
1 1 2 3 3 4 4 8 8
0 1 2 3 4 5 6 7 8
由于存在这样的二段性,可以对当前二分点mid的奇偶性进行分情况讨论:
- mid为偶数
正常情况下偶数下标的值会和下一值相同,所以如果当前值满足此条件,则证明该mid值之前没有插入单一元素。更新左右边界。 - mid为奇数
正常情况下奇数下标的值会和上一个值相同,如果满足该条件,则可以确保mid之前没有插入单一元素,更新左右边界。
算法代码:
方法一代码:
//方法1:遍历
public static int singleNonDuplicate(int[] nums) {
int len = nums.length;
for (int i = 0;i < len-1;i+=2){
if (nums[i] != nums[i + 1]){
return nums[i];
}
}
return nums[len-1];
}
时间复杂度:O(N)
空间复杂度:O(1)
方法二代码:
//方法2:二段法
public static int singleNonDuplicate(int[] nums) {
int n = nums.length;
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r >> 1;
//mid为偶数
if (mid % 2 == 0) {
if (mid + 1 < n && nums[mid] == nums[mid + 1]) {
//左侧为没有插入单个元素的数组,更新左边界
l = mid + 1;
} else {
//右侧为没有插入单个元素的数组,更新右边界
r = mid;
}
} else {
//mid为奇数
if (mid - 1 >= 0 && nums[mid] == nums[mid - 1]) {
//左侧为没有插入单个元素的数组,更新左边界
l = mid + 1;
} else {
//右侧为没有插入单个元素的数组,更新右边界
r = mid;
}
}
}
return nums[r];
}
时间复杂度:O(logN)
空间复杂度:O(1)