题目
给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。
你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度
来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/si…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
读题
- 都是整数
- 有序数组(联想到二分法)
- 大部分元素都会出现两次,只有一个数会出现一次(这里说明数组长度为奇数)
- 结果要求返回只出现一次的数
- 解决方案有时间复杂度和空间复杂度要求(时间复杂度要求容易联想到二分法)
解题
解题思路
- 感觉二分法可以解决,尝试下二分法
- 举个例子:1 1 2 3 3 4 4。长度为7,二分法取到中间值3,与他同值的3在右边,去掉3后,左边数组长度为3,右边数组长度为2,此时要找的数2在左边。取左边数组
- 得到1 1 2。二分法取中间值1,与它同值的1在左边,去掉1后,左边数组长度为0,右边数组长度为1,此时要找的数2在右边。则取右边数组
- 得到2,明显得到答案
- 多验证几个例子,发现可行,尝试编码。
php-递归解法
<?php
function singleNonDuplicate($nums)
{
if (count($nums) == 1) {
return $nums[0];
}
$l = count($nums);
$mid = intval($l / 2);
if ($nums[$mid - 1] == $nums[$mid]) {
if ($mid % 2 == 0) {
return singleNonDuplicate(array_slice($nums, 0, $mid-1));
} else {
return singleNonDuplicate(array_slice($nums, $mid + 1));
}
} elseif ($nums[$mid] == $nums[$mid + 1]) {
if ($mid % 2 == 0) {
return singleNonDuplicate(array_slice($nums, $mid + 2));
} else {
return singleNonDuplicate(array_slice($nums, 0, $mid));
}
} else {
return $nums[$mid];
}
}
print_r(singleNonDuplicate([1,2,2,3,3]));
go-常规解法
package main
import "fmt"
func singleNonDuplicate(nums []int) int {
length := len(nums)
if length == 1 {
return nums[0]
}
left, mid, right := 0, 0, length-1
for left < right {
mid = (left + right) / 2
if nums[mid] == nums[mid-1] {
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]
}
}
return nums[left]
}
func main() {
num := []int{1, 1, 2, 2, 3, 3, 4}
fmt.Println(singleNonDuplicate(num))
}
其他技巧
可以异或的数学特性解这道题(不符合时间复杂度)
- 两个相同的数异或结果为0:a^a = 0
- 0与任意数异或结果为任意数:0^a = a
- 异或满足交换律:a^b^c = a^c^b = c^a^b
package main
import (
"fmt"
)
func singleNonDuplicate(nums []int) int {
result := 0
for _, val := range nums {
result ^= val
}
return result
}
func main() {
num := []int{0, 0, 1, 2, 2, 3, 3, 4, 4}
fmt.Println(singleNonDuplicate(num))
}