137. 只出现一次的数2(Python)

题目

难度:★★★★☆
类型:数组
方法:自动状态机

传送门

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

说明:

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

示例

示例 1:

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

示例 2:

输入: [0,1,0,1,0,1,99]
输出: 99

解答

方法1:统计

直接统计每个字符出现的频率,然后返回出现频率为1的数,需要空间复杂度。

from collections import Counter
class Solution0:
    def singleNumber(self, nums):
        return [k for k, v in Counter(nums).items() if v == 1][0]

方法2:自动状态机

这里比较推荐力扣官网的一个解答,传送门,空间复杂度为1。

class Solution:
    def singleNumber(self, nums):
        seen_once = seen_twice = 0        
        for num in nums:
            seen_once = ~seen_twice & (seen_once ^ num)
            seen_twice = ~seen_once & (seen_twice ^ num)
        return seen_once

其实晦涩难懂,我们将完整的自动状态机实现出来给大家查看。

class Solution:
    def singleNumber(self, nums):
        """
        \0|        \0|         \0|
        00 ---1--> 01 --1----> 10
        ^\__________1_________/

        用00,01,10表示三个状态,即某一个数字出现的次数除以3的余数
        00状态遇到激励1,变成01状态
        01状态遇到激励1,变成10状态
        10状态遇到激励1,变成00状态
        每一种状态遇到激励0,保持当前状态不变,最后选取余数是1的情况,即01状态的后面一位作为结果
        :param nums:
        :return:
        """

        def nums2bin(nums):
            """
            将所有数字转换为等长的二进制字符串。
            :param nums:
            :return:
            """
            nums = [bin(num)[2:] for num in nums]
            l = max([len(num) for num in nums])
            nums = [num.rjust(l, '0') for num in nums]
            return nums

        def transfer_one_bit(state, activation):
            """
            根据激活值和状态转移规则,更新当前状态
            :param state: 当前状态,用两位表示
            :param activation: 当前激活值(遇到的数字)
            :return: 更新后的状态
            """

            if activation == '0':
                return state
            elif activation == '1':
                if state == '00':
                    return '01'
                elif state == '01':
                    return '10'
                elif state == '10':
                    return '00'
                else:
                    raise Exception
            else:
                raise Exception

        def transfer_all_bit(current_result, num):
            return [transfer_one_bit(cur_bit_state, act) for cur_bit_state, act in zip(current_result, num)]

        state_result = ['00'] * len(nums)                       # 初始化每个位为状态零
        for num in nums2bin(nums):                              # 遍历每个数字
            state_result = transfer_all_bit(state_result, num)  # 根据新的数字更新当前总状态

        result = ''.join([state[1] for state in state_result])  # 取出来每个状态的第二位,因为只出现一次的时候这个位是1
        return int(result, 2)                                   # 转回十进制

如有疑问或建议,欢迎评论区留言~

你可能感兴趣的:(137. 只出现一次的数2(Python))