Страницы

Поиск по вопросам

суббота, 1 февраля 2020 г.

Как осуществить слияние k сортированных списков

#python_3x #сортировка #list #память #время


Даны k отсортированных в порядке неубывания массивов натуральных чисел, каждое из
которых не превосходит 100. Требуется построить результат их слияния: отсортированный
в порядке неубывания массив, содержащий все элементы исходных k массивов.

Длина каждого массива не превосходит 10 ⋅ k.

Постарайтесь, чтобы решение работало за время k ⋅ log(k) ⋅ n, если считать, что входные
массивы имеют длину n.

Формат ввода

Первая строка входного файла содержит единственное число k, k ≤ 1024.

Каждая из следующих k строк описывает по одному массиву. Первое число каждой строки
равняется длине соответствующего массива, оставшиеся числа этой строки описывают значения
элементов этого же массива. Элементы массивов являются натуральными числами и не превосходят 100.

Формат вывода

Выходной файл должен содержать отсортированный в порядке неубывания массив, содержащий
все элементы исходных массивов.

Пример

Ввод

4
6 2 26 64 88 96 96
4 8 20 65 86
7 1 4 16 42 58 61 69
1 84

Вывод

1 2 4 8 16 20 26 42 58 61 64 65 69 84 86 88 96 96

Ограничение по времени выполнение скрипта 1 сек. для любого теста, ограничение по
используемой памяти: 10 МБ

Вот мой код:

import sys

int_str = ''
n = int(sys.stdin.readline().strip())
for i in range(int(n)):
    s = sys.stdin.readline().strip() + ' '
    count = int(s[:s.find(' ')])
    p, j = 0, 0
    for j in range(s.__len__()):
        if s[j] == ' ':
            p += 1
        if p == count+1:
            break
    int_str += s[s.find(' '):j]
    del (s,)

for i in sorted(int_str.lstrip().split(' '), key=lambda x: int(x) if x.isdigit() else 0):
    print(i, end=" ")


Ещё один вариант

import sys

n = int(sys.stdin.readline().strip())
int_list = []
for i in range(n):
    input = sys.stdin.readline().strip()
    data = list(map(int, input.split()))
    input = None
    n = data[0]
    a = data[1:n+1]
    int_list.extend(a)
    data = None

int_list.sort()

for li in int_list:
    sys.stdout.write(str(li) + ' ')
sys.stdout.write('\n')


Гномья сортировка

import sys

int_list = []
t = [0] * 101
n = int(sys.stdin.readline().strip())
for i in range(int(n)):
    s = sys.stdin.readline().strip()
    try:
        num = int(s[:s.find(' ')])
    except ValueError:
        continue
    for index, value in enumerate(s.split(' ')):
        if index == 0:
            continue
        elif index == num + 1:
            break
        try:
            t[int(value)] += 1
        except ValueError:
            pass
    del s

res = []
for i in range(101):
    res += [i] * t[i]

for r in res:
    print(r, end=' ')


Memory Limit и Time Limit близко
    


Ответы

Ответ 1



Так как в задаче есть ограничение на элементы массива: массивов натуральных чисел, каждое из которых не превосходит 100. то можно применить сортировку подсчётом, которая работает за линейное время. Но для C# возникает ещё одна проблема - это создание массива строк при считывании данных, которые на больших данных используют > 10Мб памяти. Я решила эту проблему с помощью запуска сборщика мусора. Моё решение: using System; using System.IO; namespace ConsoleApp { class Program { static void Main(string[] args) { short[] digitsCount = new short[101]; short k = Convert.ToInt16(Console.ReadLine()); string[] values; for (short i = 0; i < k; i++) { values = Console.ReadLine().Split(' '); for (short j = 1; j < values.Length; j++) { digitsCount[Convert.ToByte(values[j])]++; } GC.Collect(); } using (StreamWriter sw = new StreamWriter("output.txt")) { for (short i = 0; i < digitsCount.Length; i++) { for (short j = 0; j < digitsCount[i]; j++) { sw.Write(i + " "); } } } } } } Удачи на собеседовании!

Ответ 2



Сложность k * n Time Limit помогло убрать периодический вывод буфера, а не накопление его до N k = int(input()) count = {str(i): 0 for i in range(100)} total = 0 for list_index in range(k): a = input().split() size = int(a[0]) total += size if size > 0: for i in range(1, size + 1): count[a[i]] += 1 buff = [] for i in range(100): c = str(i) if i % 10 and buff: print(' '.join(buff), end=' ') buff = [] buff.extend([c] * count[c]) print(' '.join(buff)) Тест list + int() vs dict vs Counter from timeit import timeit from collections import Counter n = 10000000 str_list = [str(x) for x in range(n)] number = 10 print(timeit(""" for i in range(n): a[int(str_list[i]) % 100] += 1 """, setup='a = [0] * 100', number=number, globals=globals())) print(timeit(""" for i in range(n): d[str_list[i % 100]] += 1 """, setup='d = {str(i): 0 for i in range(100)}', number=number, globals=globals())) print(timeit(""" for i in range(n): d[str_list[i % 100]] += 1 """, setup='d = Counter(i for i in range(100))', number=number, globals=globals())) PyPy 3.5.3 (не понятно, почему Яндекс его не добавили): 6.919497203998617 1.7934346760011977 5.253608144004829 Python 3.7 27.728900675007026 17.81548438500613 25.83648096800607

Ответ 3



Тоже столкнулся с этой задачей. Начал с Python 3.6. Пробовал сортировку подсчетом и heapq.merge. Ни в какую не укладываюсь в 1 секунду на 20м тесте. Попробовал переписать на Go и сортировку подсчетом. Результат по времени абсолютно такой же как на Python. Видимо от языка не зависит. package main import ( "bufio" "fmt" "os" "strconv" "strings" ) func main() { const k = 100 reader := bufio.NewReader(os.Stdin) arraysNumString, _ := reader.ReadString('\n') arraysNumString = strings.TrimSuffix(arraysNumString, "\n") arraysNum, err := strconv.Atoi(arraysNumString) if err != nil { panic(err) } var counter [k]int for i := 0; i < arraysNum; i++ { inputString, _ := reader.ReadString('\n') inputString = strings.TrimSuffix(inputString, "\n") inputArray := strings.Split(inputString, " ") for idx, i := range inputArray { if idx == 0 { continue } j, err := strconv.Atoi(i) if err != nil { panic(err) } counter[j]++ } } for index, value:= range counter { for i := 0; i < value; i++ { fmt.Println(index) } } } Видимо нужно искать другой алгоритм или экономить на чтении строк.

Ответ 4



В задаче не оговорен запрет на использование стандартной библиотеки, поэтому моё решение выглядит следующим образом (для Python 3.4.3): from collections import Counter k = int(input()) a = Counter() for _ in range(k): a += Counter(map(int, input().split()[1:])) for key, c in sorted(a.items()): print("{} ".format(key) * c, end="") Ключевой момент здесь в том, что элементы в вводимых массивах не могут быть больше 100, а это значит, что количество ключей для Counter() не превысит это число. Даже в худшем случае, сортировка сотни целочисленных значений - простая задача. Опасения у меня вызывал только момент с суммированием Counter(), однако даже в последнем тесте, данный вариант затратил <5 mb памяти и уложился во время <0.7секунды.

Ответ 5



Реализация решения H. Case на основе встроенных типов. Результаты - 0.522s, 4.36Mb. n = int(input()) def counter_add(counter, value): if value in counter: counter[value] += 1 else: counter[value] = 1 counter = dict() for _ in range(n): ar = input().split() for i in ar[1:]: counter_add(counter, i) for i in range(101): i = str(i) if i in counter: print(' '.join([i] * counter[i]), end=' ')

Ответ 6



Я решила вот так - по-простому: k=int(input()) result={x:0 for x in range(0,101)} for i in range(k): current=input().split()[1:] for j in range(len(current)): cj = int(current[j]) result[cj] += 1 for key, v in result.items(): print("{} ".format(key) * v, end="")

Ответ 7



А я решил пойти путем использования одномерных векторов. Жаль, что Я не принял импорт NumPy... Пришлось тоже через сортировку подсчетом делать. Надеюсь, будет полезно и на такой вариант взглянуть. import sys import numpy as np k = sys.stdin.readline().strip() A = np.array([], dtype=np.uint8) for _ in range(int(k)): line = np.array(sys.stdin.readline().strip().split(" ")[1:], dtype=np.uint8) A = np.append(A, line) del line A = np.sort(A, kind="mergesort") A = A.tolist() print(*A)

Комментариев нет:

Отправить комментарий