【leetcode刷题】有序数组中的单一元素

636 阅读2分钟

题目

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

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

你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/si…

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

读题

  1. 都是整数
  2. 有序数组(联想到二分法)
  3. 大部分元素都会出现两次,只有一个数会出现一次(这里说明数组长度为奇数)
  4. 结果要求返回只出现一次的数
  5. 解决方案有时间复杂度和空间复杂度要求(时间复杂度要求容易联想到二分法)

解题

解题思路

  1. 感觉二分法可以解决,尝试下二分法
  2. 举个例子:1 1 2 3 3 4 4。长度为7,二分法取到中间值3,与他同值的3在右边,去掉3后,左边数组长度为3,右边数组长度为2,此时要找的数2在左边。取左边数组
  3. 得到1 1 2。二分法取中间值1,与它同值的1在左边,去掉1后,左边数组长度为0,右边数组长度为1,此时要找的数2在右边。则取右边数组
  4. 得到2,明显得到答案
  5. 多验证几个例子,发现可行,尝试编码。

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))
}