You are given a sorted array consisting of only integers where every element appears exactly twice, except for one element which appears exactly 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)的要求。既然是这个要求,所以一定是二分法做。注意到 input 有一个现象,就是落单的元素的 index 一定是偶数,所以我给出的二分法做了一点变化,end 只取了数组长度的一半,但是在找 mid 的时候我再乘以2,这样保证了 mid 一定是偶数。如果 nums[2 * mid] != nums[2 * mid + 1] ,那么说明单独的元素一定在前半段,否则就在后半段。这个题的官方题解写的很详细,我参考了方法三。
时间O(logn)
空间O(1)
Java实现
1 class Solution { 2 public int singleNonDuplicate(int[] nums) { 3 int start = 0; 4 int end = nums.length / 2; 5 while (start < end) { 6 int mid = start + (end - start) / 2; 7 if (nums[2 * mid] != nums[2 * mid + 1]) { 8 end = mid; 9 } else { 10 start = mid + 1; 11 } 12 } 13 return nums[2 * start]; 14 } 15 }
JavaScript实现
1 /** 2 * @param {number[]} nums 3 * @return {number} 4 */ 5 var singleNonDuplicate = function(nums) { 6 let start = 0; 7 let end = nums.length / 2; 8 while (start < end) { 9 let mid = Math.floor((start + end) / 2); 10 if (nums[mid * 2] != nums[mid * 2 + 1]) { 11 end = mid; 12 } else { 13 start = mid + 1; 14 } 15 } 16 return nums[start * 2] 17 };
二刷的时候我写了一个比较常规的二分法,因为第一种做法面试的时候除非遇到原题否则不太容易想得到。常规的二分法的右边界是 end = nums.length - 1,当 mid 是奇数的时候,我们会通过对其减一,强行让其变成偶数,这样如果 nums[mid] == nums[mid + 1] 的话,说明单一元素还在右边,要 start = mid + 2。这里 mid + 2 的原因在于 mid 和 mid + 1 背后指向的元素是相等的。因为会涉及到 mid + 2 的操作,所以第五行的 while 判断是 start < end 而不是 start <= end,这一点跟模板有区别。
Java实现
1 class Solution { 2 public int singleNonDuplicate(int[] nums) { 3 int start = 0; 4 int end = nums.length - 1; 5 while (start < end) { 6 int mid = start + (end - start) / 2; 7 // 强行把mid变为偶数,因为落单的数字只会在偶数index上 8 if (mid % 2 == 1) { 9 mid--; 10 } 11 if (nums[mid] == nums[mid + 1]) { 12 start = mid + 2; 13 } else { 14 end = mid - 1; 15 } 16 } 17 return nums[start]; 18 } 19 }