zoukankan      html  css  js  c++  java
  • [LeetCode] 136.只出现一次的数字

    一、问题概述

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

    说明:

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

    示例 1:

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

    示例 2:

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

    链接:https://leetcode-cn.com/problems/single-number/

    二、问题分析

    如果不对此题不加时空限制的话,可以想出一些解法,例如:

    1. 二重循环暴力查找

      每次选取数组中一个元素,再遍历整个数组看是否能找到相同的。若找不到则该元素出现一次。

      这种方法最容易想到,但在最坏的情况下会遍历(n^2)次,时间复杂度为(O(n^2))

    2. 使用hash表记录每个元素出现次数

      创建一个hash表,遍历一遍数组的同时将每个元素出现的次数记录在hash表中,之后遍历hash表从中找出出现次数为1的元素。

      这种方法可以做到线性时间复杂度,但使用了额外的空间。

    3. 排序数组再遍历

      先将数组排序,之后遍历数组,判断每个元素与相邻的元素是否相同。若该元素与左右相邻元素都不同,则此元素只出现一次。

      这种方法也是我第一反应想到的,虽然没有使用额外的空间,但使用快排的话,时间复杂度为(O(nlogn))。此外对边界条件的判断我也不是很熟练,因此代码写得也很臃肿。

    参考了大佬们的题解后,发现我漏了一个很重要的条件,就是每个元素最多重复两次!因此就可以根据异或(XOR)运算的性质来巧妙地解这道题。

    首先介绍一下异或运算有以下性质:

    • 任何数和 0 做异或运算,结果仍然是原来的数,即 (aoplus0=a)
    • 任何数和其自身做异或运算,结果是 0,即 (a oplus a=0)
    • 异或运算满足交换律和结合律,即 (a oplus b oplus a=b oplus a oplus a=b oplus (a oplus a)=b oplus0=b)

    基于此性质,我们就可以遍历一遍数组,将所有元素逐个进行异或运算。

    并根据交换律和结合律,将重复的元素两两结合,经异或运算后得到0,最后就变成:

    [0oplus0oplus0oplus ... oplus0oplus a=a ]

    因此,数组中的全部元素的异或运算结果即为数组中只出现一次的数字。

    三、涉及算法

    1. 异或(XOR)运算

    四、AC代码

    class Solution {
    public:
        int singleNumber(vector<int>& nums) {
            for (int i = 1; i < nums.size(); i++)
            {
                nums[0] ^= nums[i];
            }
            return nums[0];
        }
    };
    

    五、复杂度分析

    时间复杂度:O(n)

    空间复杂度:O(1)

  • 相关阅读:
    C# 本质论 第三章 操作符和控制流
    LeetCode Online Judge 1. Two Sum
    C# 本质论 第二章 数据类型
    C# 本质论 第一章 C#概述
    TMDS代码
    `define `ifdef `elseif的巧妙使用
    加法器(行波与超前、全加与半加)
    DCI技术
    **标识符
    电容放置问题
  • 原文地址:https://www.cnblogs.com/hanbin92381/p/leetcode-136.html
Copyright © 2011-2022 走看看