Рассчитать максимальную длину массива, чтобы среднее значение было меньше заданного значения

Я пытаюсь решить этот вопрос, но для большинства тестовых случаев получаю тайм-аут. Может ли кто-нибудь помочь мне в оптимизации этого?

Постановка задачи :

Вам дан массив A длины N. Вы должны выбрать подмножество S из данного массива A, так чтобы среднее значение S было меньше K. Вам нужно вывести максимально возможную длину S.

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

The first line of each input contains  N, length of array A.
Next line contains N space separated elements of array A.
Next line of input contains an integer Q, Number of queries.
Each following Q  lines contains a single integer K.

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

For each query, print single integer denoting the maximum possible length of the subset.

Пример ввода

5
1 2 3 4 5
5
1
2
3
4
5

Пример вывода

0
2
4
5
5

Объяснение

  1. В первом запросе нет возможного подмножества, среднее значение которого меньше 1.
  2. Во втором запросе вы можете выбрать подмножество {1,2}.
  3. В третьем запросе вы можете выбрать подмножество {1,2,3,4}.
  4. В четвертом и пятом запросах вы можете выделить полный массив {1,2,3,4,5}.

Вот мое решение:

import java.util.*;

public class Playground {
    public static void main(String args[] ) throws Exception {
        Scanner s = new Scanner(System.in);
        long n = Long.parseLong(s.nextLine());                 // Reading input from STDIN
        String[] temp = s.nextLine().trim().split(" ");
        long[] arr = new long[(int) n];
        for (int i = 0; i < n; i++) 
            arr[i] = Integer.parseInt(temp[i]);
        long q = Long.parseLong(s.nextLine());

        long[] queries = new long[(int) q];
        for (int i = 0; i < q; i++) {
            long x = Long.parseLong(s.nextLine());
            queries[i] = x;
        }
        PriorityQueue<Long> queue = new PriorityQueue<>();
        for (long x : arr)
            queue.add(x);
        for (long x : queries) {
            double avg = 0;
            List<Long> list = new ArrayList<>();
            int i = 0;
            int sum = 0;
            boolean flag = false;
            while (! queue.isEmpty()) {
                long num = queue.poll();
                i++;
                list.add(num);
                sum += num;
                avg = (double) sum / i;

                if (avg >= x) {
                    System.out.println(i - 1);
                    flag = true;
                    break;
                }

            }
            if (! flag)
                System.out.println(n);
            queue.addAll(list);
        }
    }
}
Любопытный: Если вы знаете, что n и q должны соответствовать int, почему вы используете parseLong вместо parseInt?
Andreas 19.08.2018 16:49

Да, ты прав. мы можем игнорировать это.

rishav 19.08.2018 16:53

Не используйте PriorityQueue, который вам нужно постоянно перестраивать. Просто отсортируйте массив один раз, а затем повторно используйте его для каждого запроса. --- Кроме того, деление double происходит намного медленнее, чем умножение long, поэтому if ((double) sum / i >= x) следует переписать как if (sum >= x * i). --- Не знаю, принесут ли эти две подсказки достаточный прирост производительности для своевременного выполнения задачи. Вам придется попробовать и увидеть.

Andreas 19.08.2018 16:58

Я никогда не видел смысла в том, чтобы выбрать проблему на сайте, посвященном вызову, а затем попросить кого-нибудь решить ее. Моя проблема, а не твоя. :-)

Ole V.V. 19.08.2018 17:28
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
4
676
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Легкий способ решить эту проблему - сначала отсортировать массив. После того, как вы отсортировали массив так, чтобы каждый элемент был равен последнему или больше, чем последний, решить один прогон легко:

int count = 0;
int limit = 0;
for (int i : sortedArray) {
    int diff = i - maxAvg;
    if (limit + diff < 0) {
        limit += diff;
        count++
    } else {
        break;
    }
}
System.out.println(count);

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

Сортировка массива - O(n*log(n)), и для каждого решения нужен только O(n)

Это мое полное решение со всем разбором:

public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int arrLen = Integer.parseInt(sc.nextLine());
    int[] array = new int[arrLen];
    String[] strNums = sc.nextLine().split(" ", arrLen);
    for (int i = 0; i < arrLen; i++) {
        array[i] = Integer.parseInt(strNums[i]);
    }

    Arrays.sort(array);

    int numTests = Integer.parseInt(sc.nextLine());
    for (int i = 0; i < numTests; i++) {
        int maxAvg = Integer.parseInt(sc.nextLine());
        int limit = 0;
        int count = 0;
        for (int j : array) {
            int diff = j - maxAvg;
            if (limit + diff < 0) {
                count++;
                limit += diff;
            } else {
                break;
            }
        }
        System.out.println(count);
    }
    sc.close();
}

Только выбор чисел ниже среднего не даст ответа [1,2] (среднее = 1,5) для k=2.

Andreas 19.08.2018 16:52

Спасибо, я допустил небольшую ошибку. Но я не просто выбираю числа ниже среднего. В вашем примере после первого раунда limit - это -1. (-1) + 0 - это < 0, поэтому он тоже будет выбран.

Johannes Kuhn 19.08.2018 17:08

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