Удалить элементы для заданного количества итераций

Дан массив из N целых чисел. Пройдитесь по всему массиву и выберите K позиций, содержащих одинаковые значения. Эти выбранные K затем удаляются из массива. Если мы не можем выбрать значения K, то никакие места не могут быть удалены из массива.

Задача состоит в том, чтобы минимизировать количество различных целых чисел в массиве, доступном после каждой итерации.

Для данного Q запросов, с каждым запросом с номером P. Для каждого запроса выведите количество различных целых чисел в массиве после выполнения P итераций.

1<= N <= 10^6
1<= K <= 10
1<= Q <= 10^5
0<= C <= 10^5
1 <= P <= N

Example:
N=5
K=1
Q=3

Array = [5,0,1,2,1];

Queries (Various P values):
1
5
3

Output:
3
0
1

Объяснение при P = 3:

1. First iteration, we can remove element 1 with value `5`.
2. Second iteration, we can remove element 2 with `0`.
3. Third iteration, we can remove element 4 with value `2`.

Наконец, массив содержит только два элемента со значениями 1. Таким образом, количество оставшихся различных цветов равно 1.

Это код, который я пробовал, но застрял в том, как выполнить требования:

static int getDistinctFeatures(int[] array, int size, int K, int P) {
    Map<Integer, Integer> map = new LinkedHashMap<>();
    // Count the occurrence of each element in the array
    for (int i : array) {
        map.put(i, map.getOrDefault(i, 0) + 1);
    }

    Set<Integer> keys = map.keySet();
    List<Integer> keyList = new ArrayList<>(keys);

    int index = 0;

    for (int i = 0; i < P && index < keyList.size(); i++) {
        int key = keyList.get(index);
        index++;
        int count = map.get(key);
        if (count == 1) {
            map.remove(key);
        } else {
            // What to do here
        }
    }
    return map.size();
}

Итак, если k = 2 и Array = [1,1,1,3,3,3], какой ответ будет для p = 1? Это 2?

mahbubcseju 02.07.2019 02:22

@mahbubcseju, я тоже не уверен в этом входе, экзамен дал только 3 примера входных данных. Я пытался решить для них в первую очередь.

learner 02.07.2019 02:54
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
2 933
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вот предлагаемый подход.

  1. Построить карту от value до count_of_value
  2. Узнайте, сколько значений имеют числа, НЕ кратные k. Это count_incommensurate то, от скольких значений вы не можете избавиться.
  3. Для остальных значений создайте массив по возрастанию count_of_value / k.
  4. Теперь создайте поиск по количеству итераций, сколько существует удаляемых значений.
  5. Выполните поиск.

В вашем случае эти шаги приводят к следующему. Исходная карта:

{
    0: 1,
    1: 2,
    2: 1,
    5: 1,
}

Все значения делятся на k=1, поэтому count_incommensurate = 0.

Массив отсчетов в порядке возрастания равен [1, 1, 1, 2].

Теперь мы подошли к массиву поиска. Он начинается с 0 с общего количества отсчетов, которое равно 4. Итак [4, .... Теперь мы записываем каждое число количество раз, прежде чем уменьшить, и останавливаемся на 0. Таким образом, мы получаем [4, 3, 2, 1, 1]. Другими словами

counts: [1, 1, 1, 2   ]
lookup: [4, 3, 2, 1, 1]

Если бы наши подсчеты были [1, 2, 3], мы бы вместо этого получили

counts: [1, 2   , 3      ]
lookup: [3, 2, 2, 1, 1, 1]

Но вернемся к тому, что мы на самом деле получили. [4, 3, 2, 1, 1] — это массив, начинающийся с 0, для нашего поиска, а все, что находится за его пределами, — это 0.

Теперь делаем наши поиски.

Поиск 1 плюс несоизмеримое дает нам 3 + 0 = 3.

Поиск 5 не в конце, поэтому мы получаем 0 + 0 = 0.

Поиск 3 дает нам 1 + 0 = 1.

Если мы повторим это упражнение с k=2, мы обнаружим, что count_incommensurate — это 3, а наш поисковый массив окажется [1]. (После нулевых итераций элемент 1 все еще существует.) Поскольку все поиски не в конце, мы получим 3, 3, 3 в качестве нашего ответа.

Время для этого алгоритма O(N + Q). Учитывая, что для сканирования значений требуется O(N), а для сканирования запросов — O(Q), вы не можете улучшить это более чем на постоянный коэффициент. Небольшой момент, который следует упомянуть, заключается в том, что исходный массив счетчиков (в данном случае [1, 2, 1, 1]) необходимо отсортировать, что добавляет временную сложность O(N log N) к задаче.

Как генерируется массив [4, 3, 2, 1, 1], объясните, пожалуйста. Также я потерял и не смог понять пояснение под утверждением The lookup array is (remember it is a 0-based array) [4, 3, 2, 1, 1] как выполняются поиски 1, 5, 3 и почему мы добавляем их в несоизмеримые

learner 02.07.2019 02:45

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

learner 02.07.2019 02:55

@learner Я добавил больше объяснений того, как они были сделаны в этом случае, и как они были бы другими, если бы у нас был другой массив подсчетов. Надеюсь, это поможет.

btilly 02.07.2019 02:57

Что касается того, почему мы добавляем несоизмеримое, то это потому, что мы НИКОГДА не избавляемся ни от одного из несоизмеримых элементов. Мы пытаемся удалить их, но в конечном итоге мы получаем остаток ниже k, который мы не можем удалить. Таким образом, мы отслеживаем, от скольких элементов мы можем избавиться, как быстро, и добавляем, из скольких мы убираем последний.

btilly 02.07.2019 03:01

@btilly Не могли бы вы привести здесь код, который я пропустил, читая ваше объяснение.

thealchemist 11.06.2020 20:58

@thealchemist Извините, я установил личную политику НЕ размещать код для чего-либо, что выглядит так, как будто оно исходит от онлайн-судьи.

btilly 11.06.2020 21:04

Не знал, что это исходит от онлайн-судьи.

thealchemist 11.06.2020 21:14

@thealchemist Я тоже не знаю, что это такое. Но формат вопроса, включая параметры, с которыми вы можете столкнуться, выглядит именно так.

btilly 11.06.2020 21:42

Предложенное добавление от Ликантроп: Небольшой момент, который следует упомянуть, заключается в том, что первоначальный массив счетчиков (в данном случае [1, 2, 1, 1]) необходимо отсортировать, что добавляет к проблеме временную сложность O (N log N)`. (я: мне не понравилось должно быть, но теперь проверил ваше предложение: array of counts in increasing order — Lycanthropeus вполне может быть прав насчет оценки роста во время выполнения.)

greybeard 29.12.2020 10:38

@greybeard Каждый раз, когда вы выбираете k одного и того же значения и удаляете их. Если значение встречается несколько раз, не кратное k, вы никогда не сможете удалить его последнюю копию и, следовательно, не сможете удалить это значение из массива. И Ликантроп упустил что-то важное. Счетчики находятся в диапазоне 1..N, и может быть не более O(sqrt(N)) различных счетов. Сортировка ведром сортирует это в O(N).

btilly 29.12.2020 17:56

Это ответ, который я закодировал на основе алгоритма, предложенного @btilly.

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;


class Main {
    public static void main(String args[] ) throws Exception {
           
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        String[] num_arr;
        num_arr = br.readLine().split("\\s");
        
        int [] nkq_arr = new int[3];
        for(int i=0;i<3;i++)
        {   
            nkq_arr[i] = Integer.parseInt(num_arr[i]);
        }

        int N = nkq_arr[0];
        int K = nkq_arr[1];
        int Q = nkq_arr[2];
        
        int i = 0,j = 0;

        String[] param_arr;
        param_arr = br.readLine().split("\\s");
        
        int [] arr = new int[N];
        while(i < N)
        {
            arr[i] = Integer.parseInt(param_arr[i]);
            i++;
        }

        int[] queries = new int[Q];
        while(j < Q)
        {
            queries[j] = Integer.parseInt(br.readLine());
            j++;
        }

        for(int c=0;c<Q;c++)
        {
          System.out.println(minFeatures(arr,N,K,queries[c]));
        } 

    }
    static int minFeatures (int [] arr, int N, int K, int query)
    {
      HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
      int count=0;
      for(int i=0;i<N;i++)
      {
        if (!map.containsKey(arr[i]))
        {
          map.put(arr[i],1);
          count++;
        }
        else
        {
          Integer b = map.get(arr[i]);
          b+=1;
          map.replace((Integer)arr[i],b);
        }
      }
      
      List<Integer> relevant_arr = new ArrayList();
      int improper_count=0;
      int relevant_arr_length = 0;

      for(Integer val : map.values())
      {
        if (val%K==0)
        {
          relevant_arr.add(val/K);
          relevant_arr_length++;
        }
        else
        {
          improper_count++;
        }
      }
      Collections.sort(relevant_arr);
      List<Integer> lookUp_arr = new ArrayList();

      int alpha = 0;
      int overall_length=0;

      while(alpha < relevant_arr_length)
      {
        int number_of_times = relevant_arr.get(alpha);
        int beta = number_of_times;

        while(beta > 0)
        {
          lookUp_arr.add(count);
          beta--;
          overall_length++;
        }
        count--;
        alpha++;
      }

      
      if (query > overall_length-1)
      {
        return improper_count;
      }      
      else
      {
        return improper_count + lookUp_arr.get(query);
      }
  }
}

Python Реализация алгоритма, предложенного @btilly.

from collections import defaultdict

def evaluateMin(arrQ,k,queryArr):
  ans = []
  countMap = defaultdict(lambda : 0)
  for value in arrQ:
    countMap[value] +=1
  
  counts=[]
  presentEveryTime = 0
  for value in countMap:
    if countMap[value] % k != 0:
      presentEveryTime +=1
    else:
      counts.append(int(countMap[value]/k))

  # Creating Lookup Array
  counts = sorted(counts)
  lookup = []
  # print(counts)
  appender = len(counts)
  for count in counts:
    for i in range(count):
      lookup.append(appender)
    
    if appender != 1:
      appender -=1
  # print(lookup,presentEveryTime)
  for query in queryArr:
    if query >= len(lookup):
      ans.append(0+presentEveryTime)
    else: 
      ans.append(lookup[query]+presentEveryTime)

  return ans

print(evaluateMin([5,0,1,2,1,1,1],2,[1,5,3,0,2]))

Другие вопросы по теме