簡體   English   中英

找出不在區間列表中的最小數字

[英]Find the smallest number that is not in a list of intervals

我必須找到不在區間列表中的最小數字。 例如,我有一個列表:[(2, 6), (0, 3), (9, 10)]。 我必須通過檢查從 0 到 10 的所有數字來找到最小的數字,直到找到不在這些范圍內的最小數字。 因此,數字不能介於 2 和 6(包括兩者)、0 和 3、9 和 10 之間。

我寫了一個函數,但我無法得到正確的答案。 我總是得到程序檢查的所有第一個數字,但我只需要最后一個。 我不明白為什么它不適用於回報。

intervals = [(2, 6), (0, 3), (9, 10)]
def smallest_number(intervals):
   i = 0
   while True:
      for first, second in intervals:
         if i in range(first, second + 1):
            i += 1
            print(i)

print(smallest_number(intervals))

我期望輸出 7,但我得到一個循環 7 或數字從 1 到 7,這取決於我把 print(i) 放在哪里。

這是一種方法:

from itertools import chain
intervals = [(2, 6), (0, 3), (9, 10)]

ranges = chain.from_iterable(range(i, j+1) for i, j in l)
min(set(range(10)).difference(ranges))
# 7

細節

第一步使用生成器推導式和調用range並使用每個tuple兩個元素從tuple包含的范圍創建一個set 使用itertools.chain將結果展平:

ranges = chain.from_iterable(range(i, j+1) for i, j in l)
print(list(ranges))
# {0, 1, 2, 3, 4, 5, 6, 9, 10}

現在我們只需要尋找這個集合和一個到nrange之間的差異的min

diff = set(range(10)).difference(ranges)
# {7, 8}

我這里沒有 Python 可以檢查,但您的函數似乎沒有返回任何內容,因此print(smallest_number(intervals))打印None

def smallest_number(intervals):
   i = 0
   while True:
      for first, second in intervals:
      if i in range(first, second + 1):
          i += 1
      else:
          return i

現在print(smallest_number(intervals))應該可以工作了。

在無限循環結束之前,您的代碼將打印所有在間隔中的數字,不是那些不在的數字。 嘗試這個:

def smallest_number(intervals):
    i = 0
    while True:
        for first, second in intervals:
            if i in range(first, second + 1):
                i += 1
                break # break from inner loop
        else:
            break # break from outer loop
    return i # return number

此外,雖然if i in range(first, second + 1):在 Python 3 中沒問題(而且速度很快),我寧願建議使用if first <= i <= second:

或者更短,使用nextany

def smallest_number(intervals, max_ = 10):
    return next((i for i in range(max_ + 1)
                 if not any(first <= i <= second for first, second in intervals)),
                None) # None is default if none is found

當沒有這樣的最小數字時,我的解決方案可以防止案例。

checking = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
intervals = [(2, 6), (0, 3), (9, 10)]
min_number = None

unique = set()
for left, right in intervals:
    unique.update(range(left, right + 1))

subset = set(checking) - unique
if subset:
    min_number = min(subset)

print(min_number)

如果您想要一個允許的數字列表,而不僅僅是最小的,這可能是一個不錯的選擇。

import itertools


def flatten(list_of_sublists):
    return itertools.chain.from_iterable(list_of_sublists)


def excluded_numbers(intervals):
    excluded_ranges = [range(lower, upper + 1) for lower, upper in intervals]
    excluded_numbers = set(flatten(excluded_ranges))
    return excluded_numbers


def permitted_numbers(intervals):
    excluded = excluded_numbers(intervals)
    max_excluded = max(excluded)
    candidates = set(range(max_excluded + 2))
    return candidates - excluded


def smallest_number(intervals):
    return min(permitted_numbers(intervals))

按起點對間隔進行排序(如果起點相等,則為終點)。 然后從第一個區間開始,繼續擴大右邊界,直到下一個區間的起點大於我們當前的覆蓋終點。

Take (2,6),(0,3),(9,10)
Sorting: (0,3),(2,6),(9,10)
current coverage = [0,3]

由於 3 < 6 和 2<3,我們可以將右點增加到 6,因此覆蓋率變為 [0,6] 但 6 < 9,因此 7 是不在任何間隔中的最小數字。 您還需要檢查第一個間隔的起點是否 > 0。在這種情況下,答案將為 0。

暫無
暫無

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

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