Вопрос для интервью - разбить текст на подстроки в соответствии с правилами - PullRequest
5 голосов
/ 11 июля 2010

Разделить текст на подстроки в соответствии с нижеследующими правилами:

  • а) Длина каждой подстроки должна быть меньше или равна М
  • b) Длина подстроки должна быть меньше или равна N (N
  • c) Общее количество подстрок должно быть как можно меньше

Понятия не имею, как решить этот вопрос, наверное, это связано с "динамическим программированием". Кто-нибудь может помочь мне реализовать это с помощью C # или Java? Большое спасибо.

Ответы [ 3 ]

11 голосов
/ 11 июля 2010

Идея

Жадный подход - это путь:

  • Если текущий текст пуст, все готово.
  • Возьмите первый Nперсонажи.Если какой-либо из них является цифрой, то это новая подстрока.Отрубите его и перейдите к началу.
  • В противном случае увеличьте сегмент без цифр до максимум М символов.Это новая подстрока.Отрубите его и перейдите к началу.

Доказательство

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

Случай 1) Цифра среди первых N символов.

Предположим, чтоесть вход, для которого отсечение первых N символов не может дать оптимального решения.

Greedy split:   |--N--|...
A better split: |---|--...
                      ^
                      +---- this segment can be shortened from the left side

Однако второй сегмент предполагаемого лучшего решения всегда можно сократить с левой стороны, а первыйрасширен до N символов без изменения количества сегментов.Следовательно, противоречие: это разделение не лучше, чем жадное разделение.

Случай 2) Нет цифры среди первых K (N

Предположим, что есть вход, для которого отсечение первых символов K не может дать оптимального решения.

Greedy split:   |--K--|...
A better split: |---|--...
                      ^
                      +---- this segment can be shortened from the left side

Опять же, «лучшее» разделение может быть преобразовано без изменения количества сегментов,к жадному расщеплению, что противоречит исходному предположению о том, что существует лучшее расщепление, чем жадное расщепление.

Следовательно, жадное расщепление является оптимальным.QED

Реализация (Python)

import sys

m, n, text = int(sys.argv[1]), int(sys.argv[2]), sys.argv[3]
textLen, isDigit = len(text), [c in '0123456789' for c in text]

chunks, i, j = [], 0, 0
while j < textLen:
   i, j = j, min(textLen, j + n) 
   if not any(isDigit[i:j]):
      while j < textLen and j - i < m and not isDigit[j]:
         j += 1
   chunks += [text[i:j]]
print chunks

Реализация (Java)

public class SO {
   public List<String> go(int m, int n, String text) {
      if (text == null)
         return Collections.emptyList();
      List<String> chunks = new ArrayList<String>();

      int i = 0;
      int j = 0;
      while (j < text.length()) {
         i = j;         
         j = Math.min(text.length(), j + n);
         boolean ok = true;
         for (int k = i; k < j; k++) 
            if (Character.isDigit(text.charAt(k))) {
               ok = false;              
               break;                   
            }                   
         if (ok)        
            while (j < text.length() && j - i < m && !Character.isDigit(text.charAt(j)))
               j++;                     
         chunks.add(text.substring(i, j));
      }         
      return chunks;
   }    

   @Test
   public void testIt() {
      Assert.assertEquals(
         Arrays.asList("asdas", "d332", "4asd", "fsdxf", "23"),
         go(5, 4, "asdasd3324asdfsdxf23"));
   }    
}
4 голосов
/ 11 июля 2010

Боло представил жадный алгоритм в своем ответе и попросил контрпример. Ну, нет контр-примера, потому что это совершенно правильный подход. Вот доказательство. Хотя это немного многословно, часто бывает так, что доказательство длиннее самого алгоритма:)

Давайте представим, что у нас есть ввод длины L и мы построили ответ A с помощью нашего алгоритма. Теперь предположим, что есть лучший ответ B. Т.е. у B меньше сегментов, чем у A.

Скажем, первый сегмент в A имеет длину la, а в B - lb. la> = lb, потому что мы выбрали первый сегмент в A, чтобы иметь максимально возможную длину. И если lb <<code>la, мы можем увеличить длину первого сегмента в B без увеличения общего количества сегментов в B. Это дало бы нам другое оптимальное решение B', имеющее тот же первый сегмент, что и A.

Теперь удалите этот первый сегмент из A и B' и повторите операцию для длины L' <<code>L. Делайте это, пока не останется ни одного сегмента. Это означает, что ответ A равен некоторому оптимальному решению.

0 голосов
/ 11 июля 2010

Результатом ваших вычислений будет разбиение заданного текста на короткие подстроки, содержащие цифры, и длинные подстроки, не содержащие цифры. (Это вы уже много знали).

По сути, вы будете разбивать короткие сабвуферы вокруг чисел, а затем разбивать все остальное на длинные сабы так часто, как это необходимо для соответствия критериям длины.

Ваша свобода, т. Е. То, чем вы можете манипулировать, чтобы улучшить свой результат, состоит в том, чтобы выбирать, какие символы включать в число. Если N = 3, то для каждого числа вы можете выбрать XXN, XNX или NXX. Если M равно 5 и у вас есть 6 символов перед вашим первым числом, вы захотите включить хотя бы один из этих символов в свой короткий саб, чтобы у вас не было двух «длинных» строк слева от вашего «короткого» "один, когда вы могли бы иметь только один вместо этого.

В первом приближении я бы пошел с удлинением ваших "коротких" строк влево достаточно далеко, чтобы избежать избыточных "длинных" строк. Это типичный «жадный» подход, и жадные подходы часто дают оптимальные или почти оптимальные результаты. Сделать даже лучше, чем это было бы непросто, и я не собираюсь пытаться понять, как это сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...