Найти оптимальный набор подстрок в данной строке

1

Я пытаюсь найти оптимальный набор строк для заданной строки.

Данная строка: "FEEJEEDAI"

Значения подстрок:

FE - 1
JE - 2
JEE - 3
AI - 4
DAI - 6

Возможные комбинации:

1) [FE-JE-DAI] - 1 + 2 + 6 = 9
2) [FE-JEE-DAI] - 1 + 3 + 6 = 10
3) [FE-JE-AI] - 1 + 3 + 4 = 8

ОПТИМАЛЬНАЯ КОМБИНАЦИЯ - 2) [FE-JEE-DAI] 10 баллов

Я думаю, что это должно произойти примерно так:

1) проверьте, содержит ли строка определенную подстроку:

var string = "FEEJEEDAI", substring = "JE"; string.indexOf(substring) !== -1;

2) Если true, найдите индекс

var subStringIndex = string.indexOf(substring)

3) Создайте новую tempString для построения комбинации и "обрезания" substring из string

var tempString = string.slice(subStringIndex, substring.length)

4) Итерацию через string и поиск оптимальной tempString

Я не знаю, как построить его в цикле и обрабатывать ситуацию. JE против JEE, AI против DAI

Теги:
string
algorithm
substring
mathematical-optimization

2 ответа

8

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

Это решение разделено на 3 части

  1. подготовка
  2. Сбор деталей
  3. Вычисление баллов и создание набора результатов

подготовка

В начале все подстроки строки собираются в объекте indices. Ключ - это индекс, а значение - это объект с лимитом, который является наименьшей длиной строк в массиве шаблонов. Массив шаблона содержит индекс и найденные подстроки, начинающиеся с этого индекса.

indices объекта из первого примера

{
    0: {
        limit: 2,
        pattern: [
            {
                index: 0,
                string: "FE"
            }
        ]
    },
    3: {
        limit: 2,
        pattern: [
            {
                index: 3,
                string: "JE"
            },
            {
                index: 3,
                string: "JEE"
            }
        ]
    },
    /* ... */
}

Сбор деталей

Основная идея - начать с нуля индекса с пустым массивом для сбора подстрок.

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

Из второго примера первая группа состоит из 'FE', 'EE' и 'EEJ'

string      comment
----------  -------------------------------------
01 2345678  indices
FE|EJEEDAI  
FE|         matching pattern FE  at position 0
 E|E        matching pattern EE  at position 1
 E|EJ       matching pattern EEJ at position 1
^^          all starting substrings are in the same group

С этой группой вызывается новая рекурсия с скорректированным индексом и подстрокой, объединенной с массивом деталей.

Вычисление баллов и создание набора результатов

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

Интерпретация результата

 [
    {
        parts: "0|FE|3|JE|6|DAI",
        score: 9
    },
    /* ... */
]

parts представляют собой комбинацию индексов и соответствующих строк в позиции

 0|FE|3|JE|6|DAI
 ^ ^^            at index 0 found FE
      ^ ^^       at index 3 found JE
           ^ ^^^ at index 6 found DAI

score рассчитывается с заданными весами подстрок

substring  weight
---------  ------
 FE            1
 JE            2
 DAI           6
---------  ------
score          9

В примере три возвращает 11 уникальных комбинаций.

function getParts(string, weights) {

    function collectParts(index, parts) {
        var group, limit;
        while (index < string.length && !indices[index]) {
            index++;
        }
        if (indices[index]) {
            group = indices[index].pattern;
            limit = index + indices[index].limit;
            while (++index < limit) {
                if (indices[index]) {
                    group = group.concat(indices[index].pattern);
                }
            }
            group.forEach(function (o) {
                collectParts(o.index + o.string.length, parts.concat(o.index, o.string));
            });
            return;
        }
        result.push({
            parts: parts.join('|'),
            score: parts.reduce(function (score, part) { return score + (weights[part] || 0); }, 0)
        });
    }

    var indices = {},
        pattern,
        result = [];

    Object.keys(weights).forEach(function (k) {
        var p = string.indexOf(k);
        while (p !== -1) {
            pattern = { index: p, string: k };
            if (indices[p]) {
                indices[p].pattern.push(pattern);
                if (indices[p].limit > k.length) {
                    indices[p].limit = k.length;
                }
            } else {
                indices[p] = { limit: k.length, pattern: [pattern] };
            }
            p = string.indexOf(k, p + 1);
        }
    });
    collectParts(0, []);
    return result;
}

console.log(getParts("FEEJEEDAI", { FE: 1, JE: 2, JEE: 3, AI: 4, DAI: 6 }));
console.log(getParts("FEEJEEDAI", { FE: 1, JE: 2, JEE: 3, AI: 4, DAI: 6, EEJ: 5, EJE: 3, EE: 1 }));
console.log(getParts("EEEEEE", { EE: 2, EEE: 3 }));
.as-console-wrapper { max-height: 100% !important; top: 0; }
  • 0
    Это хорошее решение. Возможно, это было бы оптимизацией, если бы на этапе предварительной обработки вы также записали наименьшую длину для каждого индекса, поэтому вам не нужно выполнять этот поиск во время рекурсивного алгоритма, который может повторяться во время альтернативных ветвей в дереве рекурсии.
  • 1
    @trincot, отличная идея, теперь с ограничением для шаблона наименьшей длины.
0

Если вы вырезаете подстроку, когда найдете их, так как некоторые подстроки являются подстроками других подстрок, сначала найдите самые большие. Например, если вы не нашли DAI, и вы найдете AI, это не может быть частью DAI. Вы хотите протестировать каждую подстроку, чтобы вы могли поместить каждую подстроку в массив и петлю через массив.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню