簡體   English   中英

遍歷列表以查找元素是否大於所有后續元素

[英]Iterating over a list to find whether an element is greater than all following elements

我目前很難嘗試計算列表中每個元素大於其所有后續元素的次數。

我嘗試用兩個例子編寫解決方案,但沒有成功。 我希望能夠用兩個循環或一個循環來做到這一點。 任何采用蠻力方法的想法都將不勝感激。 這是我到目前為止所擁有的。

兩個循環

def count_dominators(items):
    count=0
    for i in range(len(items)):
        for j in range(len(items)-1):
                if items[j]>items[i]:
                    break
                if j == len(items)-1:
                    count+=1
        if i == len(items)-1:
            count+=1
    return count

items=[42, 7, 12, 9, 2, 5]
count_dominators(items)

一個循環

def count_dominators(items):
    count=0
    largest=items[-1]
    i=len(items)-1
    while i>=0:
        if items[i] > largest:
            count+=1
            i-=1
        return count
    
items=[42, 7, 12, 9, 2, 5]
print(count_dominators(items))

這是任務:

計數支配者

def count_dominators(items):

如果items元素右側的每個元素(不僅僅是緊鄰其右側的一個元素)都嚴格小於它,則稱該元素是主導元素。 根據這個定義,列表的最后一項自動成為支配者。 這個 function 應該計算items中的元素有多少是支配者,並返回該計數。 例如, [42, 7, 12, 9, 13, 5]的支配元素是其元素42135

在開始為此函數編寫代碼之前,您應該查閱“ 畫家 Shlemiel ”的寓言,並思考這個來自更簡單時代的看似愚蠢的故事如何與今天在列表、字符串和其他序列上執行的計算問題相關聯。 這個問題將是您在本課程期間和之后將遇到的許多問題中的第一個,以說明僅使用一個循環即可在極短時間內實現 Shlemiel 使用兩個嵌套循環實現的相同最終結果的重要原則。 因此,您的工作量僅相對於items線性增加,而 Shlemiel 來回的總時間呈二次方增長,即 function 項目數的平方

items 預期結果
[42, 7, 12, 9, 2, 5] 4
[] 0
[99] 1
[42, 42, 42, 42] 1
range(10**7) 1
range(10**7, 0, -1) 10000000

試圖在 function 調用中隱藏一些 Shlemiel 算法的內部循環(這包括 Python 內置函數,例如max和列表切片)並假裝這不知何故使這些內部循環花費恆定的時間只會召喚 Compubook 標題之神帶着喧囂返回,以索取他們的 linon 執行時間份額。

這是您的第二個改進版本(對每個更改和修復都有評論):

def count_dominators(items):
    # - start with 1 smaller than last item
    # - handle empty list
    largest = items[-1] - 1 if items else 0
    count = 0

    # - use for loop
    # - use reversed(...)
    for item in reversed(items):
        if item > largest:
            count += 1
            # - update largest
            largest = item

    return count

讓我們先 go 解決天真的解決方案:

考慮列表索引i處的元素。 如果該元素大於索引大於i的所有元素,則該元素是“支配者”

def count_dominators(items):
    count = 0
    for i in range(len(items)):
        is_dom = True # Assume for now that it is a dominator
        for j in range(i+1, len(items)):   # You only need elements after the ith element
            if items[i] <= items[j]: # If elem at i is less than j, this is not a dominator
                is_dom = False
                break   # So we don't need to check any more j for this i

        if is_dom: # Only increment the count if this is a dominator
            count += 1

    return count

該解決方案以二次時間運行。

現在尋求更智能的解決方案。 我不熟悉畫家 Shlemiel 的寓言,但一個簡單的解決方案是創建另一個列表,其中該列表索引i處的元素是子列表items[i+1:]的最大值。 然后,如果原始列表的第i個元素大於新列表的第i個元素,我們就知道它是支配者。 由於我們不想隱藏max()調用中的復雜性,我們可以向后遍歷列表。

largest_vals = [0] * len(items)

largest_vals[-1] = items[-1] - 1  

largest = items[-1]
for index in range(len(items)-2, -1, -1): # Iterate backwards
    if items[index] > largest:
        largest = items[index]

    largest_vals[index] = largest

接下來,定期遍歷列表,並計算有多少元素大於它們對應的largest_vals

count = 0
for elem, lv in zip(items, largest_vals):
    if elem > lv:
        count += 1

作為 function:

def count_dominators(items):
    if not items: return 0

    largest_vals = [0] * len(items)
    
    largest_vals[-1] = items[-1] - 1  # To handle the case of the last element 
    
    largest = items[-1]
    for index in range(len(items)-2, -1, -1): # Iterate backwards from the second-to-last element to the first

        if items[index+1] > largest: # Only overwrite largest if the current element is bigger
            largest = items[index+1]
    
        largest_vals[index] = largest 

    count = 0
    for elem, lv in zip(items, largest_vals):
        if elem > lv:
            count += 1

    return count

當然,您可以通過簡單地檢查原始循環中的items[index] > largest來將其簡化為單個循環,但是如果將它們分開,則有助於可視化問題。

要測試這個:

ls = [([42,7,12,9,2,5], 4), ([], 0), ([99], 1), ([42, 42, 42, 42], 1), (list(range(10**7)), 1), (list(range(10**7, 0, -1)), 10**7)]

for input_val, expected_val in ls:
    print(count_dominators(input_val), expected_val)

這表明 function 返回所有測試用例的預期值

4 4
0 0
1 1
1 1
1 1
10000000 10000000

像您嘗試過的那樣倒退以及 Shlomo 的做法是最好的。 如果可以go倒退。 當您不能時,這里有一個替代方法,即當您有一個只能向前迭代的可迭代對象時。

def count_dominators(items):
    doms = []
    for item in items:
        while doms and item >= doms[-1]:
            doms.pop()
        doms.append(item)
    return len(doms)

我保留了一個(遞減的)列表,列出了目前所見項目的支配者。 例如,如果那是[56, 13, 2]然后我看到41 ,它會在添加為新的默認支配者之前從支配者中刪除213 那么支配者列表是[56, 41]

運行時間為 O(n)。 你可能會想“但是它有兩個嵌套循環,賦值不是告訴我這需要二次方時間嗎?” . 好吧,不,不是這種嵌套循環。 內部循環彈出一個項目,因為我們append每個項目只彈出一次,所以我們也最多彈出每個項目一次。 所以總的來說,內循環最多運行n次。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM