Найдите минимальное количество сообщений, которые нужно отправить - PullRequest
0 голосов
/ 02 мая 2019

Недавно я столкнулся с проблемой в одном из моих тестов на собеседовании. Проблема заключается в следующем.

Предположим, есть служба для отправки сообщений пользователю. Каждое сообщение имеет длину не более 30 символов. Эта служба получает полное сообщение, а затем разбивает его на вложенные сообщения, каждый размером не более 30 символов. Но есть проблема с сервисом. Это не гарантирует порядок, в котором пользователь получает суб-сообщения. Следовательно, для каждого суб-сообщения он добавляет суффикс (k / n), где k обозначает k-е суб-сообщение из n суб-сообщений. Этот суффикс также учитывается при подсчете количества символов в дополнительном сообщении, которое не может превышать 30. Найдите минимальное количество дополнительных сообщений, необходимых для отправки.

Eg-1:

сообщение: Быстрая коричневая лиса перепрыгивает через ленивую собаку

Первое под-сообщение может быть: Быстрый рывок бурой лисы (1/2) , но

вышеупомянутое неверно, поскольку оно превышает 30 символов. Это 31 символ.

Итак, правильные под-сообщения:

Быстрая коричневая лиса (1/2)

перепрыгивает через ленивую собаку (2/2)

Итак, ответ 2.

Eg-2:

сообщение: Быстрая коричневая лиса перепрыгивает через ленивую черепаху

Итак, правильные под-сообщения:

Быстрая коричневая лиса (1/3)

перепрыгивает через ленивого (2/3)

черепаха (3/3)

Итак, ответ 3.

Eg-3:

сообщение: Здравствуйте, меня зовут

дополнительное сообщение: Здравствуйте, меня зовут

Ответ = 1.

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

Мой подход: если общая длина символа строки меньше 30, верните 1. Если нет, то получите дополнительное сообщение, пока количество символов не станет 30, проверяя каждое слово. Но теперь все усложняется, поскольку я не знаю значения n в суффиксе. Есть ли более простой способ решения проблемы?

Ответы [ 2 ]

0 голосов
/ 03 мая 2019

Вы можете выполнить бинарный поиск по общему количеству вложенных сообщений.То есть, начните с двух чисел L и H, так что вы знаете, что L вложенных сообщений недостаточно, и что H вложенных сообщений достаточно, и посмотрите, достаточно ли их среднего (L + H) / 2, пытаясь построить решение попредположение о том, что задействовано так много вложенных сообщений: если это так, сделайте это новым H, в противном случае сделайте его новым L. Остановитесь, как только H = L + 1: H будет наименьшим числом работающих вложенных сообщений, поэтому создайтефактическое решение с использованием такого количества сообщений.Это потребует O (n log n) времени.

Чтобы получить начальные значения для L и H, вы можете начать с 1 и продолжать удваивать, пока не получите достаточно большое число.Первое значение, которое достаточно велико для работы, становится вашим H, а предыдущим вашим L.

Кстати, введенные вами ограничения недостаточны для обеспечения решения: например, вход, состоящий из двухслова, разделенные пробелом, не имеют решения.

0 голосов
/ 03 мая 2019

Спасибо за публикацию, мне нравятся такие проблемы.

Как уже упоминалось выше, здесь есть небольшая проблема в том, что вы не знаете, сколько строк требуется.Таким образом, вы не знаете, разрешить ли 2 (или более) цифр для номера сообщения / общего количества сообщений.Кроме того, не могли бы вы использовать шестнадцатеричное (для 16 сообщений требуется одна цифра или даже номер формата 62) (0–9, затем AZ, а затем AZ)?

Можно, конечно, использовать предположение и сказать, есливвод больше, скажем, 200 символов, тогда вы можете использовать двузначный номер сообщения, но если сообщение было одной буквой, за которой повторяется один пробел 100 раз, то вы, вероятно, могли бы избежать использования однозначных номеров сообщений.

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

Мой подход использует 2 класса:

  1. Создайте класс MessageLine, представляющий одну строку сообщения.
  2. MessageSender - класс, который собираетMessageLine (s). Имеет вспомогательный метод, который обрабатывает сообщение и возвращает список MessageLines.

Вот мав классе MessageSender.Если вы запустите его, вы можете передать сообщение в командной строке для его обработки.

package com.gtajb.stackoverflow;

import java.util.LinkedList;

public class MessageSender {

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Please supply a message to send");
            System.exit(1);
        }

        // Collect the command line parameters into a single string.
        StringBuilder sb = new StringBuilder();
        boolean firstWord = true;
        for (String s: args) {
            if (!firstWord) {
                sb.append(" ");
            }
            firstWord = false;
            sb.append(s);
        }

        // Process the input String and create the MessageSender object.
        MessageSender ms = new MessageSender(sb.toString());
        System.out.println("Input message: " + sb.toString());

        // Retrieve the blocked message and output it.
        LinkedList<MessageLine> msg = ms.getBlockedMessage();
        int lineNo = 0;
        for (MessageLine ml : msg) {
            lineNo += 1;
            System.out.printf("%2d: %s\n", lineNo, ml.getFormattedLine(msg.size()));
        }
    }

    private String msg;

    public MessageSender(String msg) {
        this.msg = msg;
        processMessage();
    }

    private LinkedList<MessageLine> blockedMessage = new LinkedList<MessageLine> ();

    public LinkedList<MessageLine> getBlockedMessage() {
        return blockedMessage;
    }

    private static final int LINE_MAX_SIZE = 30;
    /**
     * A private helper method that processes the supplied message when
     * the object is constructed.
     */
    private void processMessage() {

        // Split the message into words and work out how long the message is.
        String [] words = msg.split("\\s+");
        int messageLength = 0;
        for (String w: words) {
            messageLength += w.length();
        }
        messageLength += words.length - 1;            // Add in the number of words minus one to allow for the single spaces.

        // Can we get away with a single MessageLine?
        if (messageLength < LINE_MAX_SIZE) {
            // A single message line is good enough.
            MessageLine ml = new MessageLine(1);
            blockedMessage.add(ml);
            for (String w: words) {
                ml.add(w);
            }
        } else {
            // Multiple MessageLines will be required.
            int lineNo = 1;
            MessageLine ml = new MessageLine(lineNo);
            blockedMessage.add(ml);
            for (String w: words) {
                    // check if this word will blow the max line length.
                    // The maximum number of lines is 2. It can be anything that is > 1.
                if (ml.getFormattedLineLength(2) + w.length() + 1 > LINE_MAX_SIZE) {
                    // The word will blow the line length, so create a new line.
                    lineNo += 1;
                    ml = new MessageLine(lineNo);
                    blockedMessage.add(ml);
                }
                ml.add(w);
            }
        }
    }
}

и вот класс Message Line:

package com.gtajb.stackoverflow;

import java.util.LinkedList;

public class MessageLine extends LinkedList<String> {

    private int lineNo;
    public MessageLine(int lineNo) {
        this.lineNo = lineNo;
    }

    /**
     * Add a new word to this message line.
     * @param word the word to add
     * @return true if the collection is modified.
     */
    public boolean add(String word) {
        if (word == null || word.trim().length() == 0) {
            return false;
        }
        return super.add(word.trim());
    }

    /**
     * Return the formatted message length.
     * @param totalNumLines the total number of lines in the message.
     * @return the length of this line when formatted.
     */
    public int getFormattedLineLength(int totalNumLines) {
        return getFormattedLine(totalNumLines).length();
    }

    /**
     * Return the formatted line optionally with the line count information.
     * @param totalNumLines the total number of lines in the message.
     * @return the formatted line.
     */
    public String getFormattedLine(int totalNumLines) {

        boolean firstWord = true;
        StringBuilder sb = new StringBuilder();
        for (String w : this) {
            if (! firstWord) {
                sb.append (" ");
            }
            firstWord = false;
            sb.append(w);
        }
        if (totalNumLines > 1) {
            sb.append (String.format(" (%d/%d)", lineNo, totalNumLines));
        }
        return sb.toString();
    }
}

Я проверил ваши сценарии ипохоже, он дает правильный результат.

Дайте мне знать, если мы получим работу.: -)

...