算法: 只出现一次的数字

Posted on Sep 8, 2020

只出现一次的数字

问题描述

给定一个非空整数数组, 除了某个元素只出现一次以外, 其余每个元素均出现两次. 找出那个只出现了一次的元素.

题目地址: https://leetcode-cn.com/problems/single-number/

说明

你的算法应该具有线性时间复杂度. 你可以不使用额外空间来实现吗?

示例

输入: [2,2,1]
输出: 1
输入: [4,1,2,1,2]
输出: 4

解答

开始想的是用collection函数来统计次数, 但发现题目的说明讲到了不使用额外的空间, 所以作罢.

后来想用sort来进行排序, 再进行for num in nums进行遍历, 来判断相邻两个是否相同从而找出不同的元素, 但这样O(n)的时间复杂度就太高了. 而且严格来说sort也使用了额外的空间(见下文解释)

python的sort方法

见python源码中的sort实现

int PyList_Sort(PyObject *v)
{
    if (v == NULL || !PyList_Check(v)) {
        PyErr_BadInternalCall();
        return -1;
    }
    v = list_sort_impl((PyListObject *)v, NULL, 0);
    if (v == NULL)
        return -1;
    Py_DECREF(v);
    return 0;
}

使用的是Timsort算法, 从时间复杂度来讲, 这个算法是高效的.img

从空间复杂度来讲,需要的开销在数量大的时候会增大.

img

下面是JSE7 中Timsort实现代码中的一段话,可以很好的说明Timsort的优势:

A stable, adaptive, iterative mergesort that requires far fewer than n lg(n) comparisons when running on partially sorted arrays, while offering performance comparable to a traditional mergesort when run on random arrays. Like all proper mergesorts, this sort is stable and runs O(n log n) time (worst case). In the worst case, this sort requires temporary storage space for n/2 object references; in the best case, it requires only a small constant amount of space.

大体是说,Timsort是稳定的算法,当待排序的数组中已经有排序好的数,它的时间复杂度会小于$n log(n)$。与其他合并排序一样,Timesrot是稳定的排序算法,最坏时间复杂度是$O(n log n)$。在最坏情况下,Timsort算法需要的临时空间是$\frac{n}{2}$,在最好情况下,它只需要一个很小的临时存储空间.

最终解法

异或

  1. 交换律:a ^ b ^ c <=> a ^ c ^ b
  2. 任何数于0异或为任何数 0 ^ n => n
  3. 相同的数异或为0: n ^ n => 0

2 ^ 3 ^ 2 ^ 4 ^ 4等价于 2 ^ 2 ^ 4 ^ 4 ^ 3 => 0 ^ 0 ^3 => 3

class Solution:
    def singleNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        a = 0
        for num in nums:
            a = a ^ num
        return a