简体   繁体   English

优化 python 代码 - 在未排序的列表中搜索,需要保留嵌套循环作为索引位置

[英]Optimizing python code - searching within an unsorted list with nested loops as index positions need to be retained

I have a list (stockData) with some random positive integers then another query list (queries) that contains some positions(indexes counted from 1 and not 0) within stockData.我有一个包含一些随机正整数的列表(stockData),然后是另一个查询列表(查询),其中包含 stockData 中的一些位置(从 1 开始计数的索引而不是 0)。

Based on the 'queries', The code must identify a closest value smaller than the one at a give position.基于“查询”,代码必须识别一个最接近的值,该值小于给定 position 的值。 If there is a clash/tie, the smaller index position is preferred.如果存在冲突/平局,则首选较小的索引 position。 If no such value can be identified on either side of position, then -1 should be returned.如果在 position 的任一侧都无法识别出此类值,则应返回 -1。

Example1示例 1

stockData = [5,6,8,4,9,10,8,3,6,4]
queries = [6,5,4]

At position 6 (index=5) in stockData, value is 10, both position 5 (index=4) and position 7 (index=6) are smaller values (9 and 8 resp.) than 10, hence we choose the one at a lesser position -> [5]
At position 5 (index=4) in stockData, value is 9, position 4 (index=3) is smaller hence we choose position 4 -> [5,4]
At position 4 (index=3) in stockData, value is 4, position 8 (index=7) is only value smaller hence we choose position 8 -> [5,4,8]

Output
[5,4,8]

Example2示例 2

stockData = [5,6,8,4,9,10,8,3,6,4]
queries = [3,1,8]

Here, at position 8, the value 3 is the smallest of the list, so we return -1

Output
[2,4,-1]

Constraints约束

1 <= n <= 10^5 (n is the length of stockData)
1 <= stockData[i] <= 10^9 
1 <= q <= 10^5 (q is the length of queries)
1 <= queries[i] <= 10^9 

My code is working fine, but taking too long to execute.我的代码运行良好,但执行时间过长。 Looking for any help with optimizing it or any other corrective measures.寻求优化它或任何其他纠正措施的任何帮助。 Thanks !!谢谢 !!

My Code:我的代码:

def predictAnswer(stockData, queries):
    # convert days to index
    query_idx = [val-1 for val in queries]

    # output_day_set
    out_day = []

    for day in query_idx:
        min_price = stockData[day]
        day_found = False
        
        for i in range(1, max(day,len(stockData)-day)):
            prev = day-i
            nxt = day+i
            if prev >= 0 and stockData[prev] < min_price:
                out_day.append(prev+1)                        
                day_found = True
                break
            if nxt < len(stockData) and stockData[nxt] < min_price:
                out_day.append(nxt+1)                        
                day_found = True
                break
        
        if not day_found:
            out_day.append(-1)
    
    return out_day

Solution Approach as suggested by @Carlos: @Carlos 建议的解决方案方法:

for idx, val in enumerate(stockData):
        if val in stockDict.keys():
            stockDict[val].append(idx)
        else:
            stockDict[val] = [idx]
    
    stockDict_sortedKeys = sorted(stockDict)

For the sample input:对于样本输入:

stockData = [5,3,4,6,5,4,6,8,9,5,7]

Output: Output:

stockDict = {5: [0], 6: [1, 8], 8: [2, 6], 4: [3, 9], 9: [4], 10: [5], 3: [7]}
stockDict_sortedKeys = [3, 4, 5, 6, 8, 9, 10]

Now may be for a for a given query 'day', I would need to find the corresponding sortedData[day] and find the closest index for all the values smaller?现在可能是对于给定查询'day',我需要找到相应的 sortedData[day] 并找到所有值更小的最近索引?

You can iterate on your stockData to get the most recent previous smaller value, by keeping a heap of local minima:您可以通过保持一堆局部最小值来迭代您的stockData以获得最近的先前较小的值:

import heapq

class Data:
    def __init__(self, day, value):
        self.day = day
        self.value = value
    def __lt__(self, other):
        return self.value >= other.value
    def __repr__(self):
        return f'Data(day={self.day}, value={self.value})'

def precalc(days):
    result = []
    heap = []
    for day, value in days:
        data = Data(day, value)
        while heap and heap[0] < data:
            heapq.heappop(heap)
        result.append(heap[0].day if heap else -1)
        heapq.heappush(heap, data)
    return result

The complexity is O(n log(n)) , as each day can only be pushed/popped once.复杂度为O(n log(n)) ,因为每天只能推送/弹出一次。

To get the expected answer, you have to do it in the other direction also:要获得预期的答案,您还必须朝另一个方向进行:

def compare(f, b, q):
    if f < 0: return b
    if b < 0: return f
    if q-f <= b-q:
        return f
    else:
        return b

def predictAnswer(stockData, queries):
    forward = precalc(enumerate(stockData, 1))
    backward = list(reversed(precalc(reversed(list(enumerate(stockData, 1))))))
    return [compare(forward[q-1], backward[q-1], q) for q in queries]

This is still O(n log(n)) .这仍然是O(n log(n))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM