有序数组中的单一元素

167 阅读2分钟

这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战

leetcode 有序数组中的单一元素

给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。

请你找出并返回只出现一次的那个数。

你设计的解决方案必须满足 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

解题:读其题知其意,假设哪个单一元素的下标为x,因为数组有序并且其他元素出现两次,那么单一元素x的左边部分元素是偶数个,然后下标是从0开始,所以x的下标一定是偶数。 出现两次的元素因为数组有序,必然有相同元素是相邻的。因此我们可以二分查找到最小偶数下标并且满足nums[x]不等于nums[x+1],那这个x就是哪个单一元素了。 并且题目主要是在有序数组中查找元素,关键字有序数组、查找元素,然后还要求 O(log n) 时间复杂度因此可以考虑使用二分查找。 具体的二分查找的两个边界初始就分别为数组的边界,然后每次获取left、right边界的平均值mid来判断,需要保证mid是奇数,特别的当mid是偶数时,mid按位与运算1=0,当mid是奇数时,mid按位与运算1=1。 所以可以将mid的值重新计算:mid -= mid&1,这样可以保证mid一定是偶数了。然后比较nums[mid]和nums[mid+1]的值是否相等,如果相等就需要调整左边界,否则需要调整右边界,直到找到x下标。

class Solution {
    public int singleNonDuplicate(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int mid = (right - left) / 2 + left;
            if (nums[mid] == nums[mid ^ 1]) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return nums[left];
    }
}

或者 二分查找的时候的mid不一定要保证为偶数,就判断mid位置下标如果是奇数,就判断nums[mid]和nums[mid-1],如果相等需要调整左边界,否则调整右边界;如果mid位置下标如果是偶数, 就判断nums[mid]和nums[mid+1],如果相等需要调整左边界,否则调整右边界,最后直到找到x即可。