Leetcode540. 二分查找找出数组中只出现一次的元素

Leetcode540. Single Element in a Sorted Array

题目

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.

解题分析

这道题本身就有许多做法,但如何做到效率最高,就要看算法了。注意到题目有一个细节,数组已经是排序了的,而且题目要求我们时间复杂度为O(log n)、空间复杂度为O(1),不难想到二分查找。
既然想到了二分查找,那就得根据中间元素来做文章了。但这次题目并不仅仅要求我们找到一个目标元素,而且该元素只出现了一次。那么怎样判定这个元素出现了多少次呢?很显然,将它与前后的元素进行比较。如果都不同,那么很显然,它就是我们所要找的答案。如果与前面或者后面的元素相同,那么情况就复杂了一些。
如果与前面的元素相同,那么怎样判断只出现一次的元素在中间元素的左边还是右边呢?这里巧妙地根据其下标来判断。由于只有一个元素只出现了一次,所以如果中间元素的下标为奇数,则说明只出现一次的元素在其右边;否则在其左边。同样,如果与后面的元素相同,如果中间元素的下标为奇数,则只出现一次的元素在其左边;否则在其右边,刚好与上面的情况相反。
这里还要注意一个细节。就是中间元素为首尾两个元素的情况,这时情况的判断就少了很多。只需要判断该元素是否与相邻的元素相同。如果相同,重复上面所说的情况,如果不同,则说明该元素就是我们所要找的元素,因为不可能出现相邻的元素是只出现一次的元素的情况,如若这样,就有两个元素只出现一次,与题目要求不符。考虑了上面的情况,问题就顺利解决了。

源代码

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

以上是我对这道问题的一些想法,有问题还请在评论区讨论留言~

你可能感兴趣的:(leetcode算法)