2

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


Sample Input:

7

2 1 2 3 1 5 7


Sample Output:

3

1 2 3

1 5 7


Вроде с первой частью задачи я справился, длину наибольшего среза он мне выводит, но вторая часть программы не работает. Подскажите, что неправильно делаю?

import java.util.Scanner;

public class TestClass {

    public static void main(String[] args) throws IOException {
        Scanner in = new Scanner(System.in);
        int N = in.nextInt();
        int[] a = new int[N];
        int d = 0;
        int e = 0;
        int f = 0;
        for (int i = 0; i < N; i++) {
            a[i] = in.nextInt();
        }
        for (int b = 0; b < N - 1; b++) {
            if (a[b] > a[b + 1]) {
                e++;
                if (e >= f) {
                    f = e;
                    e = 0;
                }
            } else if (a[b] < a[b + 1]) {
                e++;
            }
        }
        {
            e++;
            if (f <= e) {
                f = e;
            }
        }
        if (f == 0) {
            System.out.println(e);
        } else {
            System.out.println(f);
        }

        int k = 0;
        int[] g = new int[f - 1];
        for (int b = 0; b < N - 1; b++) {
            while (k < f) {
                g[k] = a[b];
                if (a[b] > a[b + 1]) {
                    k = f;
                    for (int v = 0; v < f - 1; v++) {
                        g[v] = 0;
                    }
                    k = 0;
                }
            }
            k++;
        }
    }
}
  • Что значит "длина наибольшего среза"? – fedotsoldier Jun 20 '19 at 16:56
  • срез - подпоследовательность чисел, в которой каждый следующий член больше предыдущего. А длина наибольшего среза - это количество элементов, которые в этом срезе оказались. К примеру: для массива 3 3 3 1 2 3 4 1 1 2 4 Срезы: 1 2 3 4 и 1 2 4, из них срез 1 2 3 4 - длиннее, то есть длина наибольшего среза будет - 4. – Сан Саныч Jun 20 '19 at 17:10
  • Так, по крайней мере понятно, что нужно сделать. Но дебажить ваш код просто невозможно, учитывая, что у вас переменные названы a, b, c. Я не пойму как вы сами до сих пор в этом разбирались) – fedotsoldier Jun 20 '19 at 17:15
  • Откуда вы взяли такую терминологию? Срезами в некоторых языках называют подмассивы. Непрерывные. Здесь вы говорите "подпоследовательность" - а в подпоследовательности элементы могут пропускаться – MBo Jun 20 '19 at 17:21
  • Хорошо, соглашусь. Пусть будет так для простоты: Срез - это кусок подряд идущих элементов. – Сан Саныч Jun 20 '19 at 17:23

3 Answers3

5

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

Создадим второй массив, в нем будем для каждого элемента i хранить его индекс в текущей подпоследовательности. Потом запомним длину самой большой подпоследовательности, и выведем все подпоследовательности этой длины.

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

Итак, код

public static void main(String[] args) {

    int[] input = new int[]{2, 1, 2, 3, 1, 5, 7};
    int[] lens = new int[input.length];

    int max = 0;

    for(int i=1; i<input.length; i++)
    {
        if (input[i]>input[i-1])
            lens[i] = lens[i-1]+1;
        else lens[i] = 0;
        max = Math.max(lens[i], max);
    }

    System.out.println(max + 1);

    for(int i=0; i<input.length; i++)
    {
        if (lens[i] == max)
        {
            for(int j=i-lens[i]; j<=i; j++)
                System.out.print(input[j] + " ");
            System.out.println();
        }
    }
}

На выходе получаем

3
1 2 3 
1 5 7 

Крайние случаи найдите и обработайте сами :)

Вариант со считыванием из консоли

public static void main(String[] args) {

    Scanner in = new Scanner(System.in);
    int N = in.nextInt();

    int[] input = new int[N];
    for(int i=0; i<N; i++) input[i] = in.nextInt();

    int[] lens = new int[input.length];

    int max = 0;

    for(int i=1; i<input.length; i++)
    {
        if (input[i]>input[i-1])
            lens[i] = lens[i-1]+1;
        else lens[i] = 0;
        max = Math.max(lens[i], max);
    }

    System.out.println(max + 1);

    for(int i=0; i<input.length; i++)
    {
        if (lens[i] == max)
        {
            for(int j=i-lens[i]; j<=i; j++)
                System.out.print(input[j] + " ");
            System.out.println();
        }
    }
}
tym32167
  • 32,857
  • Да, спасибо, совершенно правильно Ваш код работает. Осталось только понять как эти данные не в массиве закладывать, а через консоль вводить (я имею в виду натуральное число N и далее N целых чисел. – Сан Саныч Jun 22 '19 at 07:46
  • @СанСаныч ну это вроде у вас реализовано в коде в вопросе – tym32167 Jun 22 '19 at 07:50
  • Вроде реализовано, но когда я пытаюсь упростить и попытаться ввод в консоль реализовать через: Scanner in = new Scanner(System.in); int input = in.nextInt(); int[] lens = new int[input.length]; То разумеется сыпятся ошибки... – Сан Саныч Jun 22 '19 at 07:54
  • @СанСаныч int input = in.nextInt(); в моем коде это массив, а не число – tym32167 Jun 22 '19 at 07:56
  • Точно! Соображаю туго...) А можно ли массив заменить числом? Ввести его через консоль, а уже после - массив чисел, из которого и будет выводиться и длина наибольшего среза, и содержимое среза и т. д.? Хочется понять, есть ли какой-то простой способ сделать это в одну-две строки. – Сан Саныч Jun 22 '19 at 08:02
  • нет, заменить массив чисел числом нельзя. Вам по любому надо считать сначала количество элементов, потом каждый элемент массива отдельно. Тут упрощать, по сути, нечего. Вы можете этот код считывания массива вынести в отдельный метод и переиспользовать его в будущих проектах, но что то поменять в нем у вас не получится. – tym32167 Jun 22 '19 at 08:04
  • А если попробовать завести еще двумерный массив (или 2 одномерных) для хранения информации: индекс начала среза и его длина - заполнить их сразу же пока читаются входные данные. Найти максимальное значение длины, найти все индексы начала срезов максимальной длины, вывести элементы исходного массива от стартового индекса в количестве = макс.длине. Так работать будет? – Сан Саныч Jun 22 '19 at 08:09
  • 2 одномерных массива кушают памяти 2N, двухмерный кушает NN, то есть гораздо больше, он вам не нужен. Алгоритм, что я показал, работает уже за линейное время. Радикально ускорить вы его не сможете, вы сможете только немного ускорить для конкретных входных данных (при этом замедлив для других входных данных), например, складывая максимальные срезы в отдельный список, как это сделано в соседнем ответе. – tym32167 Jun 22 '19 at 08:24
  • Массива с индексами начала вам не надо, его и так можно легко посчитать по lens, так что он просто память у вас скушает и всё. Ну, или можно убрать массив lens и сохранять только индексы начала в отдельный список - тогда получится соседний ответ. – tym32167 Jun 22 '19 at 08:25
  • Хорошо, первая часть кода у меня работает - длина наибольшего среза выводится, вторую часть я просто меняю на Ваш вариант, и теоретически все должно считаться и выводиться - но, что мне взамен Вашего int[] input = new int[]{2, 1, 2, 3, 1, 5, 7}; писать в таком случае? Ясное дело же что фигурные скобки с содержимым мне не нужны, а вот что в квадратных указывать? [f-1] - как было в моей версии - явно плохой вариант. – Сан Саныч Jun 22 '19 at 08:41
  • массив input в моем коде играет абсолютно такую же роль, как массив a в вашем вопросе, который вы уже можете считывать с консоли от юзера. – tym32167 Jun 22 '19 at 08:47
  • Все так, но не использовать Ваш массив input я не могу, как и повторно использовать свой массив а...что-то я совсем запутался... – Сан Саныч Jun 22 '19 at 08:58
  • @СанСаныч обновил ответ – tym32167 Jun 22 '19 at 09:05
  • Чёрт возьми! (прошу прощения) Все ж так просто и очевидно! Почему я затупил...это беда всех начинающих? или я один такой тормоз... – Сан Саныч Jun 22 '19 at 09:20
  • @СанСаныч все начинающие тупят, каждый по своему :) – tym32167 Jun 22 '19 at 09:21
  • Спасибо! Но, кстати, у меня получилось эту задачку и через двумерный массив сделать...кода конечно побольше получилось, и наверняка памяти съедает тоже больше, но все же работает) – Сан Саныч Jun 22 '19 at 09:24
  • @СанСаныч не советую решать задачи тяп ляп, так можно и привыкнуть. Если решаете задачу, то решайте оптимальным способом. Чтобы понять, какой способ оптимальный, а какой нет, надо учить алгоритмы и практиковаться. – tym32167 Jun 22 '19 at 09:27
  • Полностью согласен. Спасибо за совет! – Сан Саныч Jun 23 '19 at 09:43
3

Приведённый код ideone находит строго возрастающие непрерывные подмассивы (срезы) наибольшей длины и складывает их начальные индексы в список starts.

Строки из срезов длиной maxlen, начинающихся с этих индексов, я формировать не стал, думаю - это несложно.

    public static void main (String[] args) throws java.lang.Exception
    {
    Scanner in = new Scanner(System.in);
    int N = in.nextInt();
    int[] a = new int[N];
    ArrayList starts = new ArrayList();
    int startcount = 0;
    for (int i = 0; i < N; i++) {
        a[i] = in.nextInt();
    }
    int start = 0;
    int maxlen = 0;
    for (int i = 1; i <= N; i++) {
        if (i == N || a[i] <= a[i - 1]) {
            if (i - start >= maxlen) {
                if (i - start > maxlen) {
                    maxlen = i - start;
                    starts.clear();
                }
                starts.add(start);
                start = i;
            }
        }    
    }        
    for (int i = 0; i < starts.size(); i++)
        System.out.println(starts.get(i));
}
MBo
  • 53,555
  • Совершенно не те выходные данные получаются в Вашем случае. Что-то не так работает в коде...вероятно в формулах что-то не так. – Сан Саныч Jun 22 '19 at 07:22
  • Код для 2 1 2 3 1 5 7 даёт длину maxlen=3 и позиции срезов 1 и 4. Этой информации достаточно для вывода самих срезов. – MBo Jun 22 '19 at 16:11
2

Могу помочь с составлением алгоритма решения. Можете написать решение по нему или проверить свой на следование ему:

  • Разбиваете вторую строку с числами с помощью string.split(sep)
  • Превращаете массив строк в массив чисел
  • Если в массиве больше одного элемента:
    • Создаете промежуточный список типа List
    • Создаете результирующий список
    • Сохраняете максимальную длину последовательности пока как ноль
    • Первый элемент добавляете в промежуточный список
    • Проходите в цикле по массиву с числами из последовательности, начиная со второго элемента
      • Если новый элемент больше старого:
        • Сохраняете его в промежуточный список
      • Иначе:
        • Копию промежуточного списка добавляете в результирующий
        • Если максимальная длина меньше размера промежуточного:
          • Максимальную длину приравниваете к размеру промежуточного
        • Промежуточный очищаете
        • Добавляете в промежуточный текущий элемент(который больше старого)
    • Кладёте текущий промежуточный список также в результирующий
    • Его длину также сравниваете с максимальной и переопределяете максимальную, если она меньше
    • В результирующем списке оставляете только те списки, длина которых равна максимальной
    • Выводите размер результирующего списка
    • Для каждого из его вложенных списков:
      • Выводите этот список в строковом представлении
  • Иначе:
    • Печатаете единицу и сам первый элемент