算法题:查找只出现一次的数 两种方法 二分查找 时间复杂度为O(logn)

题目描述

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

这是我面试BAT其中某家广告算法工程师时的面试题,首先应该考虑的是时间复杂度和空间复杂度,且是有序数组,我首先想到的是二分查找,时间复杂度为O(logn)。

代码

方法一:二分查找,效率高,时间复杂度为O(logn)

写法1(优化之前,初步思路,步骤详细,方便理解)

import pysnooper
list1 = [1,1,2,2,3,4,4,5,5,6,6]
@pysnooper.snoop()#pysnooper是装饰器,可以修改函数,作用是打印函数的参数
def fun(list1):
    if len(list1)==0:#判读是否是空列表
        return -1
    elif len(list1)==1:#判读是否只有一个元素
        return list1[0]
    elif list1[0]!=list1[1]:#判读该数是否出现在最左边
        return list1[0]
    elif list1[-1]!=list1[-2]:#判读该数是否出现在最右边
        return list1[-1]
    else:#正常情况
        low = 0
        hi = len(list1)-1
        while min!=low:
            m = int((low+hi)/2)#取中间位置
            if m%2 == 0:
                if list1[m]==list1[m+1]:
                    low = m#扔掉一半元素
                else:
                    hi = m#扔掉一半元素
                if list1[m]!=list1[m-1] and list1[m]!=list1[m+1]:
                    return list1[m]
            else:
                if list1[m]==list1[m-1]:
                    low = m#扔掉一半元素
                else:
                    hi = m#扔掉一半元素
                if list1[m]!=list1[m-1] and list1[m]!=list1[m+1]:
                    return list1[m]
        return list1[m]

写法2(精简之后的写法)

import pysnooper
list1 = [1,1,2,2,4,5,5,6,6]
@pysnooper.snoop()#pysnooper是装饰器,可以修改函数,作用是打印函数的参数
def fun(list1):
    list1 = ['a','a']+list1+ ['b','b']
    list1.append('a')
    low = 0
    hi = len(list1)-1
    while min!=low:
        m = int((low+hi)/2)#取中间位置
        if (m%2 == 0 and list1[m]==list1[m+1]) or (m%2 == 1 and list1[m]==list1[m-1]):
            low = m#扔掉右边一半元素
        else:
            hi = m#扔掉左边一半元素
        if list1[m]!=list1[m-1] and list1[m]!=list1[m+1]:
            return list1[m]
    return list1[m]
print(fun(list1))

程序运行展示

Starting var:.. list1 = [1, 1, 2, 2, 4, 5, 5, 6, 6]
11:31:49.977043 call         4 def fun(list1):
11:31:49.978044 line         5     list1 = ['a','a']+list1+ ['b','b']
Modified var:.. list1 = ['a', 'a', 1, 1, 2, 2, 4, 5, 5, 6, 6, 'b', 'b']
11:31:49.978044 line         6     list1.append('a')
Modified var:.. list1 = ['a', 'a', 1, 1, 2, 2, 4, 5, 5, 6, 6, 'b', 'b', 'a']
11:31:49.978044 line         7     low = 0
New var:....... low = 0
11:31:49.978044 line         8     hi = len(list1)-1
New var:....... hi = 13
11:31:49.978044 line         9     while min!=low:
11:31:49.978044 line        10         m = int((low+hi)/2)#取中间位置
New var:....... m = 6
11:31:49.978044 line        11         if (m%2 == 0 and list1[m]==list1[m+1]) or (m%2 == 1 and list1[m]==list1[m-1]):
11:31:49.978044 line        14             hi = m#扔掉左边一半元素
Modified var:.. hi = 6
11:31:49.978044 line        15         if list1[m]!=list1[m-1] and list1[m]!=list1[m+1]:
11:31:49.978044 line        16             return list1[m]
11:31:49.978044 return      16             return list1[m]
Return value:.. 4

方法二:其他方法,时间复杂度太高,不太可取

list1 = [1,1,2,2,4,5,5]
def fun2(list1):
    k = min(set(list1),key = list1.count)
    print(k)
#结果:4
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Deep Learning小舟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值