Given a sorted array consisting of only integers where every element appears twice except for one element which appears once. Find this single element that appears only once.

Example 1:

Input: [1,1,2,3,3,4,4,8,8]
Output: 2

Example 2:

Input: [3,3,7,7,10,11,11]
Output: 10

Note: Your solution should run in O(log n) time and O(1) space.

这道题给我们了一个有序数组,说是所有的元素都出现了两次,除了一个元素,让我们找到这个元素。如果没有时间复杂度的限制,我们可以用多种方法来做,最straightforward的解法就是用个双指针,每次检验两个,就能找出落单的。也可以像Single Number里的方法那样,将所有数字亦或起来,相同的数字都会亦或成0,剩下就是那个落单的数字。那么由于有了时间复杂度的限制,需要为O(logn),而数组又是有序的,不难想到要用二分搜索法来做。二分搜索法的难点在于折半了以后,如何判断将要去哪个分支继续搜索,而这道题确实判断条件不明显,比如下面两个例子:

1  1  2  2  3

1  2  2  3  3

这两个例子初始化的时候left=0, right=4一样,mid算出来也一样为2,但是他们要去的方向不同,如何区分出来呢?仔细观察我们可以发现,如果当前数字出现两次的话,我们可以通过数组的长度跟当前位置的关系,计算出右边和当前数字不同的数字的总个数,如果是偶数个,说明落单数左半边,反之则在右半边。有了这个规律就可以写代码了,为啥我们直接就能跟mid+1比呢,不怕越界吗?当然不会,因为left如何跟right相等,就不会进入循环,所以mid一定会比right小,一定会有mid+1存在。当然mid是有可能为0的,所以此时当mid和mid+1的数字不等时,我们直接返回mid的数字就可以了,参见代码如下:

解法一:

class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int left = , right = nums.size() - , n = nums.size();
while (left < right) {
int mid = left + (right - left) / ;
if (nums[mid] == nums[mid + ]) {
if ((n - - mid) % == ) right = mid;
else left = mid + ;
} else {
if (mid == || nums[mid] != nums[mid - ]) return nums[mid];
if ((n - - mid) % == ) right = mid;
else left = mid + ;
}
}
return nums[left];
}
};

下面这种解法是对上面的分支进行合并,使得代码非常的简洁。使用到了亦或1这个小技巧,为什么要亦或1呢,原来我们可以将坐标两两归为一对,比如0和1,2和3,4和5等等。而亦或1可以直接找到你的小伙伴,比如对于2,亦或1就是3,对于3,亦或1就是2。如果你和你的小伙伴相等了,说明落单数在右边,如果不等,说明在左边,这方法,太叼了有木有,参见代码如下:

解法二:

class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int left = , right = nums.size() - ;
while (left < right) {
int mid = left + (right - left) / ;
if (nums[mid] == nums[mid ^ ]) left = mid + ;
else right = mid;
}
return nums[left];
}
};

下面这种解法其实跟上面的方法其实有些类似,虽然没有亦或1,但是将right缩小了一倍,但是在比较的时候,是比较mid*2和mid*2+1的关系的,这样还是能正确的比较原本应该相等的两个小伙伴的值的,其实核心思路和上面一样,参见代码如下:

解法三:

class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int left = , right = nums.size() / ;
while (left < right) {
int mid = left + (right - left) / ;
if (nums[mid * ] == nums[mid * + ]) left = mid + ;
else right = mid;
}
return nums[left * ];
}
};

下面这种方法其实跟解法二很像,没有用亦或1,但是对mid进行了处理,强制使其成为小伙伴对儿中的第一个位置,然后跟另一个小伙伴比较大小,参见代码如下:

解法四:

class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int left = , right = nums.size() - ;
while (left < right) {
int mid = left + (right - left) / ;
if (mid % == ) --mid;
if (nums[mid] == nums[mid + ]) left = mid + ;
else right = mid;
}
return nums[left];
}
};

参考资料:

https://discuss.leetcode.com/topic/83310/short-compare-nums-i-with-nums-i-1

https://discuss.leetcode.com/topic/82235/java-code-by-using-binary-search-o-log-n

https://discuss.leetcode.com/topic/82332/java-binary-search-o-log-n-shorter-than-others

https://discuss.leetcode.com/topic/87424/java-binary-search-short-7l-o-log-n-w-explanations

[LeetCode] Single Element in a Sorted Array 有序数组中的单独元素的更多相关文章

  1. 540 Single Element in a Sorted Array 有序数组中的单一元素

    给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数.示例 1:输入: [1,1,2,3,3,4,4,8,8]输出: 2 示例 2:输入: [3,3,7,7,10,1 ...

  2. [LeetCode] 26. Remove Duplicates from Sorted Array 有序数组中去除重复项

    Given a sorted array nums, remove the duplicates in-place such that each element appear only once an ...

  3. [LeetCode] Remove Duplicates from Sorted Array 有序数组中去除重复项

    Given a sorted array, remove the duplicates in place such that each element appear only once and ret ...

  4. LeetCode——Single Element in a Sorted Array

    Question Given a sorted array consisting of only integers where every element appears twice except f ...

  5. [leetcode]26. Remove Duplicates from Sorted Array有序数组去重(单个元素只出现一次)

    Given a sorted array nums, remove the duplicates in-place such that each element appear only once an ...

  6. LeetCode 977. Squares of a Sorted Array (有序数组的平方)

    题目标签:Array 题目给了我们一组 从小到大的 integers,让我们平方数字 并且 也排序成 从小到达. 因为有负数在里面,平方后,负数在array的位置会变动. 可以设left 和 righ ...

  7. LeetCode 540. 有序数组中的单一元素(Single Element in a Sorted Array) 42

    540. 有序数组中的单一元素 540. Single Element in a Sorted Array 题目描述 每日一算法2019/6/14Day 42LeetCode540. Single E ...

  8. Leetcode 540.有序数组中的单一元素

    有序数组中的单一元素 给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数. 示例 1: 输入: [1,1,2,3,3,4,4,8,8] 输出: 2 示例 2: 输入 ...

  9. Java实现 LeetCode 540 有序数组中的单一元素(位运算入门)

    540. 有序数组中的单一元素 给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数. 示例 1: 输入: [1,1,2,3,3,4,4,8,8] 输出: 2 示例 ...

随机推荐

  1. Android 的消息队列模型

    Android 的消息队列模型 Android是参考Windows的消息循环机制来实现Android自身的消息循环的.    Android通过Looper.Handler来实现消息循环机制,Andr ...

  2. drbd(一):简介和安装

    本文目录:1.drbd简介2.drbd工作原理和术语说明 2.1 drbd工作原理 2.2 drbd复制协议模型 2.3 drbd设备的概念 2.4 drbd资源角色 2.5 drbd工作模式 2.6 ...

  3. Beta冲刺随笔集合

    Beta冲刺随笔集合 项目Beta预备 Beta冲刺第一天 Beta冲刺第二天 Beta冲刺第三天 Beta冲刺第四天 Beta冲刺第五天 Beta冲刺第六天 Beta冲刺第七天 用户调查报告 Bet ...

  4. 个人作业2——NBA 2k18案例分析

    产品:篮球体育类游戏NBA 2k18 选择理由:这款游戏是<NBA 2k>的正统续作,自己和身边的朋友都对篮球比较感兴趣,经常看NBA,所以近几年的版本都有购买下载,加上游戏中人物动作比较 ...

  5. Mysql数据库的触发程序

    /** **创建表 */ CREATE TABLE test1(a1 INT); CREATE TABLE test2(a2 INT); CREATE TABLE test3(a3 INT NOT N ...

  6. DML数据操作语言之增加,删除,更新

    1.数据的增加 数据的增加要用到insert语句  ,基本格式是: insert into <表名> (列名1,列名2,列名3,......) values (值1,值2,值3,..... ...

  7. 学习UI的总结

    学习前端有一段时间了,一直在看书上的理论知识,而实战项目却很少.老师常说,想要知道自己的实力有多少,知识掌握了多少,最好的方法就是去实践了,实践出真知嘛.于是在学习中,总要是通过项目的实践以及理论知识 ...

  8. LeetCode & Q66-Plus One-Easy

    Array Description: Given a non-negative integer represented as a non-empty array of digits, plus one ...

  9. 移动端H5活动页优化方案

    背景 项目:移动端H5电商项目 痛点:慢!!! 初始方案:最基本的图片懒加载,静态资源放到cdn,predns等等已经都做了.但是还是慢,慢在哪? 显而易见的原因:由于前后端分离,所有的数据都由接口下 ...

  10. EasyUI datagrid 使用小结

    用了 EasyUI 框架一段时间了,这个前端框架用起来还是挺方便的,也有很多现成的控件,看看官方文档应该还是能比较快用起来的. 在这里记录一下一些常用的控件的方法,遇到过的bug或者当初耗了一点时间来 ...