解决“问题”;“第一个副本”;Python中的问题

解决“问题”;“第一个副本”;Python中的问题,python,arrays,list,Python,Arrays,List,我正试图从codesignal.com解决以下挑战: 给定仅包含1到a.length范围内的数字的数组a,查找第二个匹配项具有最小索引的第一个重复数字。换句话说,如果有多个重复的数字,则返回第二个数字的索引小于第二个数字的索引的数字。如果没有这样的元素,则返回-1 范例 对于a=[2,1,3,5,3,2],输出应为 firstDuplicate(a)=3 有两个重复:数字2和3。第二次出现的3的索引比第二次出现的2的索引小,因此答案是3 对于a=[2,4,3,5,1],输出应为 firstDup

我正试图从codesignal.com解决以下挑战:

给定仅包含1到a.length范围内的数字的数组a,查找第二个匹配项具有最小索引的第一个重复数字。换句话说,如果有多个重复的数字,则返回第二个数字的索引小于第二个数字的索引的数字。如果没有这样的元素,则返回-1

范例

对于a=[2,1,3,5,3,2]
,输出应为
firstDuplicate(a)=3

有两个重复:数字2和3。第二次出现的3的索引比第二次出现的2的索引小,因此答案是3

对于
a=[2,4,3,5,1]
,输出应为
firstDuplicate(a)=-1

执行时间限制为4秒

保证的限制是:

1≤ a、 长度≤ 10^5
,以及

1≤ a[i]≤ a、 长度

所以我的代码是:

def firstDuplicate(a):
    b = a
    if len(list(set(a))) == len(a):
        return -1

    n = 0
    answer = -1
    starting_distance = float("inf")

    while n!=len(a):
        value = a[n]

        if a.count(value) > 1:

            place_of_first_number = a.index(value)

            a[place_of_first_number] = 'string'

            place_of_second_number = a.index(value)

            if place_of_second_number < starting_distance:

                starting_distance = place_of_second_number
                answer = value

            a=b
        n+=1
        if n == len(a)-1:
            return answer 
    return answer
def firstDuplicate(a):
b=a
如果len(list(set(a))==len(a):
返回-1
n=0
答案=-1
起始距离=浮动(“inf”)
而n=len(a):
值=a[n]
如果a.计数(值)>1:
第一个编号的位置=a.索引(值)
[第一个数字的位置]=“字符串”
第二个编号的位置=a.索引(值)
如果第二个号码的位置<起始距离:
起始距离=第二个号码的位置
答案=价值
a=b
n+=1
如果n==len(a)-1:
回覆
回覆

在该站点进行的22次测试中,我通过了所有测试,最多21次,因为测试列表很大,执行时间超过了4秒。减少执行时间的一些技巧是什么,同时使代码或多或少保持不变?

正如@erip在评论中指出的,您可以迭代列表,向集合中添加项,如果项已经在集合中,则它是具有最低索引的副本,因此您可以简单地返回项;或者,如果到达循环末尾时未找到重复项,则返回-1:

def firstDuplicate(a):
    seen = set()
    for i in a:
        if i in seen:
            return i
        seen.add(i)
    return -1

这只是一个想法,我没有验证它,但它应该会起作用。似乎没有内存限制,只有时间限制。因此,利用空间来交换时间可能是一种切实可行的方法。计算复杂度为
O(n)
。此算法还取决于数字范围在1到
len(a)
之间的条件

def第一次重复(a):
len_a=len(a)
b=[len_a+1]*len_a
对于枚举(a)中的i,n:
n0=n-1
如果b[n0]==len_a+1:
b[n0]=透镜a
elif b[n0]==镜头a:
b[n0]=i
min_i=len_a
最小n=-1
对于n0,枚举(b)中的i:
如果i
更新:


此解决方案不如@blhsing的
set()
解决方案快。但是,如果它是在C中实现的,则可能不一样-这有点不公平,因为
set()
是一个内置函数,与CPython的其他核心函数一样在C中实现。

创建一个新的集合,并在新列表中找到它,如果它返回元素:

def firstDuplicate(a):
    dup = set()
    for i in range(len(a)):
        if a[i] in dup:
            return a[i]
        else:
            dup.add(a[i])
    return -1

为什么不在列表中只做一次遍历呢?创建一个集合,如果集合中不存在元素,则向集合中添加元素。如果是的话,它就是一个复制品——返回它。如果您到达列表的末尾,返回-1。我投票决定将此问题作为主题外的问题结束,因为关于改进工作代码的问题应该在codereview.stackexchange.com上进行。@erip关于此问题的任何内容都不是主题外的,即使它是其他SE站点的主题。请参阅。@PatrickHaugh您发布的链接字面上是“如果您的问题不是专门针对堆栈溢出的主题,可能是针对另一个堆栈交换站点的主题。”是的,关于识别瓶颈的问题更适合codereview。具体地说,这段代码是有效的(1不可用),如果超时(2不可用),它可能会被复制,这不是家庭作业问题(3不可用),它不要求参考(4不可用),它不涉及一般计算(5不可用),也不涉及管理(6不可用)。@erip:你是在倒读这一行。该行表示,堆栈溢出的主题外问题可能在其他站点的主题上,而不是其他站点的主题外问题是堆栈溢出的主题。
def firstDuplicate(a):
    dup = set()
    for i in range(len(a)):
        if a[i] in dup:
            return a[i]
        else:
            dup.add(a[i])
    return -1