渣渣刷题之路--single-number

20200908–牛客网leetcode专题刷题之路–Python篇

非计算机专业的渣渣,只自学了Python,所以没有其他的解法,基础也比较差,做得不好的地方,希望大家多多指点。

single-number

题目描述

现在有一个整数类型的数组,数组中素只有一个元素只出现一次,其余的元素都出现两次。

注意:

你需要给出一个线性时间复杂度的算法,你能在不使用额外内存空间的情况下解决这个问题么?

示例输入:

[1, 0, 1]

要求输出

0

大致思路及思考

思路一

不知道大佬们看到题目会想到什么,作为渣渣,第一眼想到的是,Python列表自带的count函数,但是时间复杂度至少都是O(n),而且还没有算count函数的时间复杂度(本来想google下list的count实现原理,但是死活没找到,不过查到某大神说count时间复杂度是O(n)),这样来看的话,我们这种方法时间复杂度就是O(n^2),并不能满足题意。

思路二

(其实是偷偷看大神解题思路,顺便学习下解题思想)原来是用到了位运算–异或(^)运算,异或运算性质:

  1. 满足交换律
  2. 相同两个数异或为0(二进制表示)
  3. 0异或一个数为那个书本身
    异或运算实例(相同为0, 不同为1):
#!usr/bin/python
2 ^ 3 = 1
0000 0010  ^  0000 0011   =  0000 0001
4 ^ 8 = 12
0000 0100  ^  0000 1000  =  0000 1100

而这里就主要利用第三条性质,0异或一个数为这个数本身。大致思路就是先定义一个结果为0,再遍历列表对每个数都去求异或,最终得到的就是单独的那个数。附上代码:

#!usr/bin/python
# coding: utf8

def getSingleNumber(li):
    res = 0
    for i in range(len(li)):
        res ^= li[i]
    return res

if __name__ == "__main__":
    # 获取输入
    li = input()
    # 由于给定的输入为[1, 0, 1], 所以对其切片切割
    li = li[1:-1]
    # 再用map函数将其封装为列表
    li = list(map(int, li.split(',')))
    print(getSingleNumber(li))

这样的话时间复杂度就只有O(n)啦,满足题意。
不过这样的话,好像又有点不对,大家考虑一下,如果给定输入的数组里面最大次数不是两次呢?这样的话异或就不能解决了。所以需要注意前置条件(要求的数组或列表必须满足出那个单数外,其余各数的重复次数皆为2

先给自己一个小目标吧,一周工作日至少4道题,周末至少4道题,今天只是个开始,写博客的意义就是大家一起监督。
对啦,今天遇到的知识点,下来还要去复习下,python中的位运算。

位运算

位运算,计算机内所有的数都以二进制存储,位运算就是对二进制位的操作。

  • (<<) 按位左移,左移n位相当于乘以2的n次方
  • (>>) 按位右移 ,左移n位相当于除以2的n次方
  • (&) 按位与,都为1结果为1,否则为0
  • (|) 按位或, 有1结果为1,否则为0
  • (^) 按位异或, 相同为0,不同为1
  • (~) 按位取反,二进制位0和1结果位互换

实例如下:

#!usr/bin/python
# coding: utf8

5 << 3 = 5 * 2^3 = 40
8 >> 2 = 8 // 2^2 = 2  # 这里需要注意python3的整除和地板除
4 & 2 = 0100 & 0010 = 0000 = 0
5 | 2 = 0101 | 0010 = 0110 = 6
7 ^ 3 = 0111 ^ 0011 = 0100 = 4
# 二进制数在内存中以补码的形式存储,正数符号位为0,原码=补码=反码
# 负数,反码就是把原码的每一位取反;补码就是反码的基础上,末位+1,负数的符号位为1
~6 = ~ 0 0110 = 1 1001 = 反码1 1001 + 1 = 1 1010 = -10

今天的学习就到这里,不要忘了按时复习哦!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值