【LeetCode学习笔记】136. 只出现一次的数字

1. 题目描述

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

示例 1:

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

示例 2:

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


2. 解题记录

2.1【2020/03/22 - 6596ms - 5.00%】

        很容易想到用 for 遍历整个数组,对每个元素使用 list.count() 计数,一旦遇到数量为1的即为目标数字。但也明白,这样效率很低 —— count() 要不断遍历整个数组/列表计数,且存在很多重复计数的冗余过程。验证一下,果然极慢:

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        # 太过暴力, 毫无优雅
        for num in nums:
            if nums.count(num) == 1:
                return num

2.2【2020/03/22 - 44ms - 87.51%】

        鉴于上述方法太过暴力,不够优雅,可以试图再优化一下,毕竟解本题法特别多。使用最好用的模块之一 ——collections 简化计数过程,果然效果不错:

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        # 实例化一个 Counter 对象
        a = collections.Counter(nums)
        # Counter.most_common([N]):按 value 大小返回一个TopN列表, 若不指定N, 则返回所有元素
        # 表示取最后一个元素 (即 value 最小的元素的 key)         
        return a.most_common()[-1][0]  

        Counter 类乃至 collections 模块都是极好用的工具,十分推荐学习!详见:http://www.pythoner.com/205.html


2.3【2020/03/22 - 36ms - 97.67%】

        其它模块固然好用,但为了锻炼思考的过程,还是尽量用常见语法好了。事实上,时间主要耗费在遍历过程中,为此,需要在尽量少的遍历次数下完成查找。以下使用了一种常见思路 —— “状态指示器 indicator”,先对列表排序,再遍历,但凡有元素被遇见的次数不满足2,即为仅出现一次的数。其实,使用 nums[i] 和 nums[i+1] 这种长度为2的滑动窗口逐次判断也一样。

# 排序 + 遍历 + 指示器/计数器 indicator
class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        nums.sort()  # 从小到大排序
        indicator = 2  # 初始计数
        cur_num = nums[0]  # 初始 cur_num
        for i in nums:
            # 如果本值等于 cur_num
            if i == cur_num:
                indicator -= 1  # 计数-1
            elif indicator == 1:  # 如果只出现过一次(计数只-1)
                return cur_num  # 只出现一次的数在前中部
            else:
                cur_num = i  # 否则, 又遇到一对数
                indicator = 1  # 因为本次判断见过一次了, 只需判断是否又出现一次
        # 只出现一次的数在末尾
        return cur_num

        注意,这类方法具有很强的泛化性,能够应用在多种问题上,如 137.只出现一次的数字II、260.只出现一次的数字III 等,都可以稍作修改就投入使用。当然,由于具体问题具体分析,性能肯定会因题而异。


2.4【2020/03/22 - 36ms - 97.67%】

        最后,再借鉴一下他人的优秀成果。这里用到了一个《数字逻辑电路》中“位运算”的重要性质:某数被同一个数异或运算两次,结果不变。例如, a = 1,b = a^2 = 1^2= 3,c = b^2 = a^2^2 = 1^2^2 =1,注意这里的 ^ 是 Python 按位异或运算符,运算结果,相同为0,相异为1。

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        res = 0
        # 完整遍历一次即可
        for num in nums:
            res = res ^ num  #  ^ 按位异或运算符:相同为0, 相异为1
        return res

        由此可见,当具备足够的经验和技巧时,就能够抽象化问题,从而找到最为简洁、优雅的思路实现问题的间接解决,在难度更高的问题上尤为如此。这还需要持之以恒地学习,而非一上来就无奈地暴力解题。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值