当前位置:网站首页>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)。
边栏推荐
- Network security - password cracking
- Anna: Beibei, can you draw?
- Sweet talk generator, regular greeting email machine... Open source programmers pay too much for this Valentine's day
- DQL basic operation
- DDL basic operation
- Everything file search tool
- His experience in choosing a startup company or a big Internet company may give you some inspiration
- 网络安全-漏洞与木马
- Swift development learning
- Analyzing several common string library functions in C language
猜你喜欢

Niuniu's ball guessing game (dynamic planning + prefix influence)

Some functions of applet development

NCTF 2018 part Title WP (1)

Smart management of Green Cities: Digital twin underground integrated pipe gallery platform

Vant implements a simple login registration module and a personal user center
![[data mining] task 2: mimic-iii data processing of medical database](/img/ad/4e7b253d60b29351e3ef252ee5230f.png)
[data mining] task 2: mimic-iii data processing of medical database

Sweet talk generator, regular greeting email machine... Open source programmers pay too much for this Valentine's day

¢ growth path and experience sharing of getting an offer

Huakaiyun (Zhiyin) | virtual host: what is a virtual host

Asian Games countdown! AI target detection helps host the Asian Games!
随机推荐
LabVIEW安装第三方VISA软件后NI VISA失效
[camera topic] complete analysis of camera dtsi
MySQL learning 03
微信小程序开发工具 POST net::ERR_PROXY_CONNECTION_FAILED 代理问题
[Yu Yue education] Jiujiang University material analysis and testing technology reference
Ni visa fails after LabVIEW installs the third-party visa software
Network security - Trojan horse
How is the mask effect achieved in the LPL ban/pick selection stage?
Redis:Redis的简单使用
Sweet talk generator, regular greeting email machine... Open source programmers pay too much for this Valentine's day
全链路数字化转型下,零售企业如何打开第二增长曲线
In the face of difficult SQL requirements, HQL is not afraid
浏览器是如何对页面进行渲染的呢?
Anna: Beibei, can you draw?
Analysis, use and extension of open source API gateway apisex
When the epidemic comes, how to manage the team as a leader| Community essay solicitation
word插入公式/endnote
Basic operation of view
Take you ten days to easily complete the go micro service series (I)
[data mining] task 1: distance calculation