• ,

level19.lesson10.bonus03, прошу совета, в вопросе оптимизации алгоритма. Какими инструментами его можно упростить?

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

package com.javarush.test.level19.lesson10.bonus03;

/* Знакомство с тегами
Считайте с консоли имя файла, который имеет HTML-формат
Пример:
Info about Leela <span xml:lang="en" lang="en"><b><span>Turanga Leela
</span></b></span><span>Super</span><span>girl</span>
Первым параметром в метод main приходит тег. Например, "span"
Вывести на консоль все теги, которые соответствуют заданному тегу
Каждый тег на новой строке, порядок должен соответствовать порядку следования в файле
Количество пробелов, \n, \r не влияют на результат
Файл не содержит тег CDATA, для всех открывающих тегов имеется отдельный закрывающий тег, одиночных тегов нету
Тег может содержать вложенные теги
Пример вывода:
<span xml:lang="en" lang="en"><b><span>Turanga Leela</span></b></span>
<span>Turanga Leela</span>
<span>Super</span>
<span>girl</span>

Шаблон тега:
<tag>text1</tag>
<tag text2>text1</tag>
<tag
text2>text1</tag>

text1, text2 могут быть пустыми
*/

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Solution {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String s = reader.readLine();
        reader.close();
        String tag = args[0];
        String f = null;

        BufferedReader in = new BufferedReader(new FileReader(s));
        StringBuilder line = new StringBuilder();
        while ((f = in.readLine()) != null){
            line.append(f);
        }
        in.close();

        Pattern p = Pattern.compile("<" + tag);
        Matcher m = p.matcher(line);
        Pattern p1 = Pattern.compile("</" + tag);
        Matcher m1 = p1.matcher(line);

        ArrayList<Integer> listnach = new ArrayList<>();//начало строки, 
        ArrayList<Integer> listkon = new ArrayList<>();
        ArrayList<Integer> obw = new ArrayList<>();

        while (m.find() && m1.find()){
            listnach.add(m.start());//начало строки которое начинается на "<" + tag
            listkon.add(m1.start());//конец строки которая заканчивается на "</" + tag
        }

        obw.addAll(listkon);
        obw.addAll(listnach);//объединение списков, чтобы видеть где начало и конец, для выставления флагов
        Collections.sort(obw);

        for (int i = 0; i < listnach.size(); i++) {
            int count = 1;
            int j = obw.indexOf(listnach.get(i));//берем первое открытие тэга
            for (j = j + 1; j < obw.size(); j++) {
                if (listnach.contains(obw.get(j))){//ищем следующее значение из общего списка, если
                    count++;                       //из общего следующим является начальный элемент, то
                    continue;                      //увеличиваем флаг на 1
                }
                if (listkon.contains(obw.get(j))){// тут ищем закрывающий тег, для вывода его на экран
                    count--;
                    if (count == 0){
                        System.out.println(line.substring(listnach.get(i), obw.get(j)) + "</" + tag + ">");
                        break;
                    }
                    continue;
                }
            }
        }
    }
}
  • ,

package com.javarush.test.level18.lesson03.task*

После решения задач люблю смотреть как решали их на форумах.
Все первые пять задач из 18 уровня (task01… task05) на побайтное чтение файлов и их разбор.
Считайте имя файла, найдите максимумы-минимумы и выведите результаты…

Во всех топиках и github репозиториях (те кто собирает свои решения ) используются коллекции:
List (чаще всего), Set-ы и TreeSet-ы (чтобы хранилось в отсортированном порядке). И везде идет чтение очередного байта из файла в List/Set…

Да, все правильно. Решение будет принято. Почти все из нас создадут текстовый файл и поместят в него что-то наподобие «123456123». Некоторые пойдут чуть дальше и натравят код на реальный текстовый файл (например книжку в ASCII). Мы все, пройдем через исправление ошибок перед тем как нажать зеленую галочку для проверки на сервере. Увидим заветное «задача принята» или с досадой увидев что тест не прошел и быстро найдем мелочь в коде программы, наподобие вывода с новой строки вместо вывода через пробел. И побежим дальше решать очередную задачу.

А теперь остановимся. Подумаем. Взглянем на содержимое жесткого диска компьютера. Много ли на нем файлов размеров в 10 байт? Не удивлюсь, если у многих есть файлы и на 20+Gb, например HD фильм. А теперь — натравите ваш код на него… который добавит побайтно 20 миллиардов раз в List и знайте, что каждый элемент List-а занимает или 6 или 12 байт. Сколько, говорите у вас оперативной памяти на ПК?

Некоторые пойдут дальше. И будут в этих задачах использовать TreeSet-ы. У них накладные расходы на элемент всего 32 или 64 байта, зато он убьет дубли (повторяющиеся значения байты в файле). Но не забывайте, что при вставке он будет сортировать свои элементы или искать по красно-черному дереву (способ организации хранения элементов в нем с учетом сортировки). А это не просто запись-чтение. И это будет выполнено 20 миллиардов раз!

Нам сделали упор на коллекциях. О удобстве их применения. Мы потихоньку узнаем о удобных методах, которые нам могут в 2-3 строчки кода найти, отсортировать, отсечь, добавить… Изучать и применять их выгодно.
Но для подобных простых задач они излишни, а в при переносе на возможные реальные объемы данных — бесполезны, а порой и вредны.

Немного отвлечемся от данных задач. Представьте вы на собеседовании. Вам ставят задачу — вывести (не важно, на экран или в файл) отсортированный большой по размеру массив байт (размерности 0 < N < миллиарда) и вывести его. Вопросы:
  • сколько операций циклов вам необходимо и сколько операций сравнения для построения такого массива
  • cколько займет в памяти отсортированный массив?

Правильные ответы: на первый — ни одного сравнения и один цикл, на второй — 1 килобайт (можно и меньше).

Подробности в коде на «отсутствующую» шестую задачу в блоке (по аналогии с первыми пятью, чтобы не было прямого копи-пасты при решениях существующих задач):
/* Сортировка байт
Ввести с консоли имя файла
Считать все байты из файла.
Не учитывая повторений - отсортировать их по байт-коду в убывающем порядке.
Вывести на экран
Закрыть поток ввода-вывода

Пример байт входного файла
44 83 44

Пример вывода
83 44
*/

...
public class Solution {
    public static void main(String[] args) throws Exception {
        FileInputStream inputStream = new FileInputStream(new BufferedReader(new InputStreamReader(System.in)).readLine());

        long[] arrBytes = new long[256];
        // Считываем массив
        while (inputStream.available() > 0) arrBytes[inputStream.read()]++;
        // Выводим отсортированный по байт-коду в обратном порядке
        for (int i = 255; i >= 0 ; i--)
            if (arrBytes[i] > 0) System.out.print(i + " ");

        inputStream.close();
    }


Думаю, что все уже поняли. Не забывайте, что часто в двоичном мире наших задач встречаются привычные на первый взгляд огромные объекты, состоящие из ограниченного числа составных элементов. И осознание сего факта может вам сильно упростить в некоторых случаях решение.

Давайте, не будем палить из пушек по воробьям!

P.S. Можете заминусовать или как тут принято за излишнюю резкость, но не смог удержаться.
  • ,

com.javarush.test.level08.lesson08.task05

Можно ли оптимизировать код метода removeItemFromMapByValue так, чтобы в нем не создавалась копия карты:

public static void removeItemFromMapByValue(HashMap<String, String> map, String value)
        {
            HashMap<String, String> copy = new HashMap<String, String>(map);
            for (Map.Entry<String, String> pair: copy.entrySet())
            {
                if (pair.getValue().equals(value))
                    map.remove(pair.getKey());
            }
        }

Почему?

Boxing/Unboxing в цикле

При изучении основ Java я частенько сталкивался с различными рекомендациями по использованию типов данных.

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

Для начала стоит сказать пару слов о JVM. JVM является стековой машиной. Грубо говоря, каждый раз, когда мы что-то делаем с переменными – они сначала помещаются в стек операндов, который формируется для каждого метода, а затем производятся необходимые вычисления.

Не вдаваясь в детали выглядит это так:

Существует ли тайм менеджмент для программиста?

Задумался о тайм менеджменте для программиста, как его осуществлять практически?
Вот бывает сидишь над каким-то багом, который для тебя не очевиден и тратишь на него целую прорву времени, тупо «бьешься головой об стену»… А потом становится обидно до слез что столько времени было потрачено впустую, потому что совсем не там копал.
То же самое время можно было потратить на изучение какой-то темы, в это время можно было что-то новое узнать, ан нет — ловишь эти гнусные баги ((
Как же всё-таки оптимизировать процесс обучения, освоения нового материала и повысить навыки практического программирование?
  • ,

Руководство пользователя IntelliJ IDEA. Основы рефакторинга.

Основы рефакторинга

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

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