当前位置:网站首页>Leetcode(540)——有序数组中的单一元素
Leetcode(540)——有序数组中的单一元素
2022-07-03 01:33:00 【SmileGuy17】
Leetcode(540)——有序数组中的单一元素
题目
给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。
你设计的解决方案必须满足 O ( log n ) O(\log n) O(logn) 时间复杂度和 O ( 1 ) O(1) 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 1 1 <= nums.length <= 1 0 5 10^5 105
- 0 0 0 <= nums[i] <= 1 0 5 10^5 105
题解
方法一:全数组的二分查找
思路
由于给定数组有序 且 常规元素总是两两出现,因此如果不考虑“特殊”的单一元素的话,我们有结论:成对元素中的第一个所对应的下标必然是偶数,成对元素中的第二个所对应的下标必然是奇数。
然后再考虑存在单一元素的情况,假如单一元素所在的下标为 x x x,那么下标 x x x 之前(左边)的位置仍满足上述结论,而下标 x x x 之后(右边)的位置由于 x x x 的插入,导致结论翻转。
假设只出现一次的元素位于下标 x x x,由于其余每个元素都出现两次,因此下标 x x x 的左边和右边都有偶数个元素,数组的长度是奇数。
由于数组是有序的,因此数组中相同的元素一定相邻。对于下标 x x x 左边的下标 y y y,如果 nums [ y ] = nums [ y + 1 ] \textit{nums}[y] = \textit{nums}[y + 1] nums[y]=nums[y+1],则 y y y 一定是偶数;对于下标 x x x 右边的下标 z z z,如果 nums [ z ] = nums [ z + 1 ] \textit{nums}[z] = \textit{nums}[z + 1] nums[z]=nums[z+1],则 z z z 一定是奇数。由于下标 x x x 是相同元素的开始下标的奇偶性的分界,因此可以使用二分查找的方法寻找下标 x x x。
初始时,二分查找的左边界是 0 0 0,右边界是数组的最大下标。每次取左右边界的平均值 mid \textit{mid} mid 作为待判断的下标,根据 mid \textit{mid} mid 的奇偶性决定和左边或右边的相邻元素比较:
- 如果 mid \textit{mid} mid 是偶数,则比较 nums [ mid ] \textit{nums}[\textit{mid}] nums[mid] 和 nums [ mid + 1 ] \textit{nums}[\textit{mid} + 1] nums[mid+1] 是否相等;
- 如果 mid \textit{mid} mid 是奇数,则比较 nums [ mid − 1 ] \textit{nums}[\textit{mid} - 1] nums[mid−1] 和 nums [ mid ] \textit{nums}[\textit{mid}] nums[mid] 是否相等。
如果上述比较相邻元素的结果是相等,则 mid < x \textit{mid} < x mid<x,调整左边界,否则 mid ≥ x \textit{mid} \ge x mid≥x,调整右边界。调整边界之后继续二分查找,直到确定下标 x x x 的值。得到下标 x x x 的值之后, nums [ x ] \textit{nums}[x] nums[x] 即为只出现一次的元素。
细节(小技巧)——不需要判断 mid \textit{mid} mid 的奇偶性
利用按位异或的性质,可以得到 mid \textit{mid} mid 和相邻的数之间的如下关系,其中 ⊕ \oplus ⊕ 是按位异或运算符:
- 当 mid \textit{mid} mid 是偶数时, mid + 1 = mid ⊕ 1 \textit{mid} + 1 = \textit{mid} \oplus 1 mid+1=mid⊕1;
- 当 mid \textit{mid} mid 是奇数时, mid − 1 = mid ⊕ 1 \textit{mid} - 1 = \textit{mid} \oplus 1 mid−1=mid⊕1。
因此在二分查找的过程中,不需要判断 mid \textit{mid} mid 的奇偶性, mid \textit{mid} mid 和 mid ⊕ 1 \textit{mid} \oplus 1 mid⊕1 即为每次需要比较元素的两个下标。
因为 0 ⊕ 1 0 \oplus 1 0⊕1 的结果为 1 1 1 ,所以不用担心左侧会越界。又因为 m i d = ( l + r ) / 2 mid = (l+r)/2 mid=(l+r)/2 所以 m i d mid mid 的值是向下取整,不会出现右侧访问数组越界。
代码实现
Leetcode 官方题解:
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int l = 0, r = nums.size()-1, mid;
while(l < r){
mid = (l+r)/2;
if(nums[mid] == nums[mid^1])
l = mid + 1;
else r = mid;
}
return nums[l];
}
};
我自己的(用长度来判定):
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
// 找到 mid 判断其左右区间的长度,找到长度为奇数的继续查找下去
// 比如 [1,1,2,3,3,4,4] mid 为第一个3,然后判断它和与它相同的数值的右边区间的长度是否为奇数,是则查找,不是则查找另一个
int l = 0, r = nums.size()-1, mid, n = nums.size();
while(l <= r){
mid = (l+r)/2;
if(mid != 0 && nums[mid] == nums[mid-1]){
if((r-mid)%2 == 0) r = mid-2;
else l = mid+1;
}else if(mid != n-1 && nums[mid] == nums[mid+1]){
if((r-mid+1)%2 == 0) r = mid-1;
else l = mid+2;
}else break;
}
return nums[mid];
}
};
复杂度分析
时间复杂度: O ( l o g n ) O(logn) O(logn),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要在全数组范围内二分查找,二分查找的时间复杂度是 O ( log n ) O(\log n) O(logn)。
空间复杂度: O ( 1 ) O(1) O(1)。
方法二:偶数下标的二分查找
思路
由于只出现一次的元素所在下标 x x x 的左边有偶数个元素,因此下标 x x x 一定是偶数,可以在偶数下标范围内二分查找。二分查找的目标是找到满足 nums [ x ] ≠ nums [ x + 1 ] \textit{nums}[x] \ne \textit{nums}[x + 1] nums[x]=nums[x+1] 的最小的偶数下标 x x x,则下标 x x x 处的元素是只出现一次的元素。
初始时,二分查找的左边界是 0 0 0,右边界是数组的最大偶数下标,由于数组的长度是奇数,因此数组的最大偶数下标等于数组的长度减 1 1 1。
每次取左右边界的平均值 mid \textit{mid} mid 作为待判断的下标,如果 mid \textit{mid} mid 是奇数则将 mid \textit{mid} mid 减 1 1 1,确保 mid \textit{mid} mid 是偶数。
比较 nums [ mid ] \textit{nums}[\textit{mid}] nums[mid] 和 nums [ mid + 1 ] \textit{nums}[\textit{mid} + 1] nums[mid+1] 是否相等,如果相等则 mid < x \textit{mid} < x mid<x,调整左边界,否则 mid ≥ x \textit{mid} \ge x mid≥x,调整右边界。调整边界之后继续二分查找,直到确定下标 x x x 的值。
得到下标 x x x 的值之后, nums [ x ] \textit{nums}[x] nums[x] 即为只出现一次的元素。
细节
考虑 mid \textit{mid} mid 和 1 1 1 按位与运算的结果,其中 & \& & 是按位与运算符:
- 当 mid \textit{mid} mid 是偶数时, mid & 1 = 0 \textit{mid}~\&~1 = 0 mid & 1=0;
- 当 mid \textit{mid} mid 是奇数时, mid & 1 = 1 \textit{mid}~\&~1 = 1 mid & 1=1。
因此在得到 mid \textit{mid} mid 的值之后,将 mid \textit{mid} mid 的值减去 mid & 1 \textit{mid}~\&~1 mid & 1,即可确保新得到的 mid \textit{mid} mid 是偶数。如果原来的 mid \textit{mid} mid 是偶数则值不变,如果原来的 mid \textit{mid} mid 是奇数则值减 1 1 1。
代码实现
Leetcode 官方题解:
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int low = 0, high = nums.size() - 1;
while (low < high) {
int mid = (high - low) / 2 + low;
mid -= mid & 1;
if (nums[mid] == nums[mid + 1]) {
low = mid + 2;
} else {
high = mid;
}
}
return nums[low];
}
};
复杂度分析
时间复杂度: O ( log n ) O(\log n) O(logn),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要在偶数下标范围内二分查找,二分查找的时间复杂度是 O ( log n ) O(\log n) O(logn)。
空间复杂度: O ( 1 ) O(1) O(1)。
边栏推荐
- 【Camera专题】OTP数据如何保存在自定义节点中
- Bottleneck period must see: how can testers who have worked for 3-5 years avoid detours and break through smoothly
- [shutter] shutter debugging (debugging control related functions | breakpoint management | code operation control)
- In the face of difficult SQL requirements, HQL is not afraid
- 2022 spring "golden three silver four" job hopping prerequisites: Software Test interview questions (with answers)
- [camera special topic] Hal layer - brief analysis of addchannel and startchannel
- Swift development learning
- [North Asia data recovery] data recovery case of raid crash caused by hard disk disconnection during data synchronization of hot spare disk of RAID5 disk array
- Caused by: com. fasterxml. jackson. databind. exc.MismatchedInputException: Cannot construct instance o
- 疫情當頭,作為Leader如何進行團隊的管理?| 社區征文
猜你喜欢
Take you ten days to easily complete the go micro service series (I)
Everything file search tool
Visual yolov5 format data set (labelme JSON file)
小程序开发的部分功能
One of the C language practical projects is greedy snake
His experience in choosing a startup company or a big Internet company may give you some inspiration
深度学习笔记(持续更新中。。。)
Wechat applet development tool post net:: err_ PROXY_ CONNECTION_ Failed agent problem
Redis:Redis的简单使用
What are the differences between software testers with a monthly salary of 7K and 25K? Leaders look up to you when they master it
随机推荐
When the epidemic comes, how to manage the team as a leader| Community essay solicitation
网络安全-信息收集
Network security - talking about security threats
File class (check)
[data mining] task 3: decision tree classification
Network security - Information Collection
Ni visa fails after LabVIEW installs the third-party visa software
ByteDance data Lake integration practice based on Hudi
网络安全-扫描
Network security - scanning and password explosion 2
Depth (penetration) selector:: v-deep/deep/ and > > >
函数的定义和调用、this、严格模式、高阶函数、闭包、递归
Comment le chef de file gère - t - il l'équipe en cas d'épidémie? Contributions communautaires
es6 filter() 数组过滤方法总结
去除网页滚动条方法以及内外边距
[fluent] hero animation (hero animation use process | create hero animation core components | create source page | create destination page | page Jump)
网络安全-DNS欺骗与钓鱼网站
Storage basic operation
Query product cases - page rendering data
力扣(LeetCode)183. 从不订购的客户(2022.07.02)