1. 程式人生 > >Leetcode540. 二分查詢找出陣列中只出現一次的元素

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]; } } } } };

以上是我對這道問題的一些想法,有問題還請在評論區討論留言~