3 ответа

Лучший ответ

Это теперь O (n), или использование Counter.__isub__ все еще мешает?

Это ожидаемый случай O (n), за исключением того, что когда Counter.__isub__ отбрасывает неположительные значения, он проходит каждый ключ , чтобы сделать это. Вам лучше просто вычесть 1 из значения ключа «обычным» способом и проверить c[k] вместо k in c. (c[k] равен 0 для k not in c, поэтому вам не нужна проверка in.)

if c[k]:
    c[k] -= 1
else:
    result.append(k)

Есть ли решение O (n), которое позволяет избежать создания этого дополнительного ограничения?

Только если входные данные отсортированы, в этом случае стандартный вариант слияния слиянием может это сделать.

Есть ли у Python лучший тип данных "bag", чем collections.Counter?

collections.Counter - сумка Питона.

2
user2357112 supports Monica 6 Янв 2017 в 23:04

Я бы использовал счетчик, но я бы сделал это немного по-другому, и я бы сделал это итеративно ...

def bag_sub(big_list, sublist):
    sublist_counts = Counter(sublist)
    result = []
    for item in big_list:
        if sublist_counts[item] > 0:
            sublist_counts[item] -= 1
        else:
            result.append(item)
    return result

Это очень похоже на ваше решение, но, вероятно, неэффективно создавать новый счетчик каждый раз, когда вы хотите уменьшить счет на что-либо. 1

Кроме того, если вам не нужно возвращать список, рассмотрите функцию генератора ...

Это работает до тех пор, пока все элементы в list_big и sublist могут быть хэшированы. Это решение O(N + M), где N и M являются длинами list_big и sublist соответственно.

Если элементы не могут быть хэшированы, вам не повезет, если у вас нет других ограничений (например, входные данные отсортированы с использованием того же критерия). Если ваши входные данные отсортированы, вы можете сделать что-то похожее на стадию слияния сортировки слиянием, чтобы определить, какие элементы из bag_sub находятся в sublist.

1 Обратите внимание, что Counter также ведут себя очень похоже на defaultdict(int), поэтому совершенно нормально искать элемент в счетчике, которого там еще нет.

3
mgilson 6 Янв 2017 в 22:37
  1. Удаление элемента из списка длины N - это O (N), если список неупорядочен, потому что вы должны его найти.
  2. Следовательно, удаление k элементов из списка длины N является O (kN), если мы сосредоточимся на «разумных» случаях, когда k << N.

Так что я не вижу, как вы могли бы получить это до O (N).

Краткий способ написать это:

new_list = [x for x in list_big if x not in sublist]

Но это все еще O (кН).

-1
Lagerbaer 6 Янв 2017 в 22:00